CRTP!!!! Totally untested
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
This commit is contained in:
110
.clang-format
Normal file
110
.clang-format
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
---
|
||||||
|
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
|
||||||
|
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: 2
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 19
|
||||||
|
PenaltyBreakComment: 300
|
||||||
|
PenaltyBreakFirstLessLess: 120
|
||||||
|
PenaltyBreakString: 1000
|
||||||
|
PenaltyBreakTemplateDeclaration: 10
|
||||||
|
PenaltyExcessCharacter: 60
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 5
|
||||||
|
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
|
||||||
|
---
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -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
|
||||||
|
3
cpplint.cfg
Normal file
3
cpplint.cfg
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Allow references to be used to change values
|
||||||
|
filter=-runtime/references
|
||||||
|
filter=-build/namespaces
|
@@ -42,7 +42,7 @@
|
|||||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
@@ -68,8 +68,8 @@
|
|||||||
#define GSM_PIN ""
|
#define GSM_PIN ""
|
||||||
|
|
||||||
// Set phone numbers, if you want to test SMS and Calls
|
// Set phone numbers, if you want to test SMS and Calls
|
||||||
//#define SMS_TARGET "+380xxxxxxxxx"
|
// #define SMS_TARGET "+380xxxxxxxxx"
|
||||||
//#define CALL_TARGET "+380xxxxxxxxx"
|
// #define CALL_TARGET "+380xxxxxxxxx"
|
||||||
|
|
||||||
// Your GPRS credentials, if any
|
// Your GPRS credentials, if any
|
||||||
const char apn[] = "YourAPN";
|
const char apn[] = "YourAPN";
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
|
|
||||||
// Default heartbeat interval for GSM is 60
|
// Default heartbeat interval for GSM is 60
|
||||||
// If you want override this value, uncomment and set this option:
|
// If you want override this value, uncomment and set this option:
|
||||||
//#define BLYNK_HEARTBEAT 30
|
// #define BLYNK_HEARTBEAT 30
|
||||||
|
|
||||||
// Select your modem:
|
// Select your modem:
|
||||||
#define TINY_GSM_MODEM_SIM800
|
#define TINY_GSM_MODEM_SIM800
|
||||||
|
@@ -52,14 +52,14 @@
|
|||||||
#define TINY_GSM_RX_BUFFER 1024
|
#define TINY_GSM_RX_BUFFER 1024
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
//#define LOGGING // <- Logging is for the HTTP library
|
// #define LOGGING // <- Logging is for the HTTP library
|
||||||
|
|
||||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||||
//#define TINY_GSM_YIELD() { delay(2); }
|
// #define TINY_GSM_YIELD() { delay(2); }
|
||||||
|
|
||||||
// Define how you're planning to connect to the internet
|
// Define how you're planning to connect to the internet
|
||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
@@ -217,7 +217,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 +246,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 +301,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) {
|
||||||
|
@@ -57,18 +57,18 @@
|
|||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
//#define LOGGING // <- Logging is for the HTTP library
|
// #define LOGGING // <- Logging is for the HTTP library
|
||||||
|
|
||||||
// Range to attempt to autobaud
|
// Range to attempt to autobaud
|
||||||
#define GSM_AUTOBAUD_MIN 9600
|
#define GSM_AUTOBAUD_MIN 9600
|
||||||
#define GSM_AUTOBAUD_MAX 115200
|
#define GSM_AUTOBAUD_MAX 115200
|
||||||
|
|
||||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||||
//#define TINY_GSM_YIELD() { delay(2); }
|
// #define TINY_GSM_YIELD() { delay(2); }
|
||||||
|
|
||||||
// Define how you're planning to connect to the internet
|
// Define how you're planning to connect to the internet
|
||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
|
@@ -49,18 +49,18 @@
|
|||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
//#define LOGGING // <- Logging is for the HTTP library
|
// #define LOGGING // <- Logging is for the HTTP library
|
||||||
|
|
||||||
// Range to attempt to autobaud
|
// Range to attempt to autobaud
|
||||||
#define GSM_AUTOBAUD_MIN 9600
|
#define GSM_AUTOBAUD_MIN 9600
|
||||||
#define GSM_AUTOBAUD_MAX 115200
|
#define GSM_AUTOBAUD_MAX 115200
|
||||||
|
|
||||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||||
//#define TINY_GSM_YIELD() { delay(2); }
|
// #define TINY_GSM_YIELD() { delay(2); }
|
||||||
|
|
||||||
// Define how you're planning to connect to the internet
|
// Define how you're planning to connect to the internet
|
||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
|
@@ -60,7 +60,7 @@
|
|||||||
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
//SoftwareSerial SerialAT(2, 3); // RX, TX
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
#define GSM_AUTOBAUD_MAX 115200
|
#define GSM_AUTOBAUD_MAX 115200
|
||||||
|
|
||||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||||
//#define TINY_GSM_YIELD() { delay(2); }
|
// #define TINY_GSM_YIELD() { delay(2); }
|
||||||
|
|
||||||
// Define how you're planning to connect to the internet
|
// Define how you're planning to connect to the internet
|
||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
@@ -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()) {
|
||||||
|
@@ -47,7 +47,7 @@
|
|||||||
#define TINY_GSM_RX_BUFFER 650
|
#define TINY_GSM_RX_BUFFER 650
|
||||||
|
|
||||||
// See all AT commands, if wanted
|
// See all AT commands, if wanted
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Define the serial console for debug prints, if needed
|
// Define the serial console for debug prints, if needed
|
||||||
#define TINY_GSM_DEBUG SerialMon
|
#define TINY_GSM_DEBUG SerialMon
|
||||||
@@ -57,10 +57,10 @@
|
|||||||
#define GSM_AUTOBAUD_MAX 115200
|
#define GSM_AUTOBAUD_MAX 115200
|
||||||
|
|
||||||
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
// Add a reception delay - may be needed for a fast processor at a slow baud rate
|
||||||
//#define TINY_GSM_YIELD() { delay(2); }
|
// #define TINY_GSM_YIELD() { delay(2); }
|
||||||
|
|
||||||
// Uncomment this if you want to use SSL
|
// Uncomment this if you want to use SSL
|
||||||
//#define USE_SSL
|
// #define USE_SSL
|
||||||
|
|
||||||
// Define how you're planning to connect to the internet
|
// Define how you're planning to connect to the internet
|
||||||
#define TINY_GSM_USE_GPRS true
|
#define TINY_GSM_USE_GPRS true
|
||||||
@@ -210,7 +210,7 @@ void loop() {
|
|||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
client.println();
|
client.println();
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
// Print available data
|
// Print available data
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
|
@@ -12,15 +12,15 @@
|
|||||||
#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
|
// #define TINY_GSM_RX_BUFFER 512
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
|
|
||||||
// Uncomment this if you want to see all AT commands
|
// Uncomment this if you want to see all AT commands
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Uncomment this if you want to use SSL
|
// Uncomment this if you want to use SSL
|
||||||
//#define USE_SSL
|
// #define USE_SSL
|
||||||
|
|
||||||
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
||||||
#define SerialMon Serial
|
#define SerialMon Serial
|
||||||
@@ -108,7 +108,7 @@ void loop() {
|
|||||||
client.print(String("Host: ") + server + "\r\n");
|
client.print(String("Host: ") + server + "\r\n");
|
||||||
client.print("Connection: close\r\n\r\n");
|
client.print("Connection: close\r\n\r\n");
|
||||||
|
|
||||||
unsigned long timeout = millis();
|
uint32_t timeout = millis();
|
||||||
while (client.connected() && millis() - timeout < 10000L) {
|
while (client.connected() && millis() - timeout < 10000L) {
|
||||||
// Print available data
|
// Print available data
|
||||||
while (client.available()) {
|
while (client.available()) {
|
||||||
|
@@ -18,16 +18,16 @@
|
|||||||
#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
|
// #define TINY_GSM_RX_BUFFER 512
|
||||||
|
|
||||||
#include <TinyGsmClient.h>
|
#include <TinyGsmClient.h>
|
||||||
#include <ArduinoHttpClient.h>
|
#include <ArduinoHttpClient.h>
|
||||||
|
|
||||||
// Uncomment this if you want to see all AT commands
|
// Uncomment this if you want to see all AT commands
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
// Uncomment this if you want to use SSL
|
// Uncomment this if you want to use SSL
|
||||||
//#define USE_SSL
|
// #define USE_SSL
|
||||||
|
|
||||||
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
// Set serial for debug console (to the Serial Monitor, speed 115200)
|
||||||
#define SerialMon SerialUSB
|
#define SerialMon SerialUSB
|
||||||
|
@@ -28,7 +28,7 @@
|
|||||||
#define SerialAT Serial1
|
#define SerialAT Serial1
|
||||||
|
|
||||||
// Uncomment this if you want to see all AT commands
|
// Uncomment this if you want to see all AT commands
|
||||||
//#define DUMP_AT_COMMANDS
|
// #define DUMP_AT_COMMANDS
|
||||||
|
|
||||||
|
|
||||||
#ifdef DUMP_AT_COMMANDS
|
#ifdef DUMP_AT_COMMANDS
|
||||||
|
@@ -6,129 +6,128 @@
|
|||||||
* @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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#include <TinyGsmClientSIM800.h>
|
#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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
#define TINY_GSM_MODEM_HAS_GPS
|
||||||
#include <TinyGsmClientSIM808.h>
|
#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
|
#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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
#define TINY_GSM_MODEM_HAS_GPS
|
||||||
#include <TinyGsmClientSIM7000.h>
|
#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
|
#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
|
#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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#include <TinyGsmClientUBLOX.h>
|
#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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#include <TinyGsmClientSaraR4.h>
|
#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
|
#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
|
#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
|
#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
|
#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_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_GPS
|
#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
|
#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_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_WIFI
|
#define TINY_GSM_MODEM_HAS_WIFI
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#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
|
#define TINY_GSM_MODEM_HAS_GPRS
|
||||||
#define TINY_GSM_MODEM_HAS_SSL
|
#define TINY_GSM_MODEM_HAS_SSL
|
||||||
#include <TinyGsmClientSequansMonarch.h>
|
#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
|
||||||
|
@@ -6,31 +6,23 @@
|
|||||||
* @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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,112 +31,101 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmA6
|
class TinyGsmA6
|
||||||
{
|
: public TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||||
|
friend class TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmA6;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmA6& modem) {
|
|
||||||
init(&modem);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmA6* modem) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = -1;
|
|
||||||
sock_connected = false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
uint8_t newMux = -1;
|
|
||||||
sock_connected = at->modemConnect(host, port, &newMux, timeout_s);
|
|
||||||
if (sock_connected) {
|
|
||||||
mux = newMux;
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
}
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse(maxWaitMs);
|
|
||||||
rx.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { stop(1000L); }
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Inner Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientA6 : public GsmClient {
|
||||||
|
friend class TinyGsmA6;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GsmClientA6() {}
|
||||||
|
|
||||||
|
explicit GsmClientA6(TinyGsmA6& modem) {
|
||||||
|
init(&modem, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(TinyGsmA6* modem, uint8_t) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = -1;
|
||||||
|
sock_connected = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
uint8_t newMux = -1;
|
||||||
|
sock_connected = at->modemConnect(host, port, &newMux, timeout_s);
|
||||||
|
if (sock_connected) {
|
||||||
|
mux = newMux;
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
}
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse(maxWaitMs);
|
||||||
|
rx.clear();
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
// Doesn't support SSL
|
||||||
|
|
||||||
private:
|
/*
|
||||||
TinyGsmA6* at;
|
* Constructor
|
||||||
uint8_t mux;
|
*/
|
||||||
bool sock_connected;
|
public:
|
||||||
RxFifo rx;
|
explicit TinyGsmA6(Stream& stream) : stream(stream) {
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
TinyGsmA6(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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("&FZ")); // Factory + Reset
|
// sendAT(GF("&FZ")); // Factory + Reset
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
|
|
||||||
sendAT(GF("E0")); // 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,7 +133,8 @@ 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());
|
||||||
@@ -162,272 +144,184 @@ public:
|
|||||||
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 thisHasSSL() {
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWifi() {
|
bool thisHasWifi() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
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
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
String getSimCCIDImpl() {
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+CCID"));
|
sendAT(GF("+CCID"));
|
||||||
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_IMEI_GSN()
|
/*
|
||||||
|
* Generic network functions
|
||||||
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
|
*/
|
||||||
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
|
public:
|
||||||
sendAT(GF("+CPIN?"));
|
RegStatus getRegistrationStatus() {
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
return (RegStatus)getRegistrationStatusXREG("CREG");
|
||||||
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)
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
|
RegStatus s = getRegistrationStatus();
|
||||||
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
|
}
|
||||||
|
|
||||||
String getOperator() {
|
/*
|
||||||
sendAT(GF("+COPS=3,0")); // Set format
|
* GPRS functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||||
|
const char* pwd = NULL) {
|
||||||
|
gprsDisconnect();
|
||||||
|
|
||||||
|
sendAT(GF("+CGATT=1"));
|
||||||
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
|
|
||||||
|
// TODO(?): wait AT+CGATT?
|
||||||
|
|
||||||
|
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||||
|
waitResponse();
|
||||||
|
|
||||||
|
if (!user) user = "";
|
||||||
|
if (!pwd) pwd = "";
|
||||||
|
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
||||||
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
|
|
||||||
|
sendAT(GF("+CGACT=1,1"));
|
||||||
|
waitResponse(60000L);
|
||||||
|
|
||||||
|
sendAT(GF("+CIPMUX=1"));
|
||||||
|
if (waitResponse() != 1) { return false; }
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool gprsDisconnectImpl() {
|
||||||
|
// Shut the TCP/IP connection
|
||||||
|
sendAT(GF("+CIPSHUT"));
|
||||||
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
sendAT(GF("+CGATT=0"));
|
||||||
|
if (waitResponse(5000L) == 1) { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String getOperatorImpl() {
|
||||||
|
sendAT(GF("+COPS=3,0")); // Set format
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
sendAT(GF("+COPS?"));
|
sendAT(GF("+COPS?"));
|
||||||
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
|
||||||
return "";
|
streamSkipUntil('"'); // Skip mode and format
|
||||||
}
|
|
||||||
streamSkipUntil('"'); // Skip mode and format
|
|
||||||
String res = stream.readStringUntil('"');
|
String res = stream.readStringUntil('"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Generic network functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
|
||||||
|
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
|
||||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GPRS functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
|
||||||
gprsDisconnect();
|
|
||||||
|
|
||||||
sendAT(GF("+CGATT=1"));
|
|
||||||
if (waitResponse(60000L) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// TODO: wait AT+CGATT?
|
|
||||||
|
|
||||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
|
||||||
waitResponse();
|
|
||||||
|
|
||||||
if (!user) user = "";
|
|
||||||
if (!pwd) pwd = "";
|
|
||||||
sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
|
||||||
if (waitResponse(60000L) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("+CGACT=1,1"));
|
|
||||||
waitResponse(60000L);
|
|
||||||
|
|
||||||
sendAT(GF("+CIPMUX=1"));
|
|
||||||
if (waitResponse() != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
|
||||||
// Shut the TCP/IP connection
|
|
||||||
sendAT(GF("+CIPSHUT"));
|
|
||||||
if (waitResponse(60000L) != 1)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
for (int i = 0; i<3; i++) {
|
|
||||||
sendAT(GF("+CGATT=0"));
|
|
||||||
if (waitResponse(5000L) == 1)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool isGprsConnected() {
|
|
||||||
sendAT(GF("+CGATT?"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int res = stream.readStringUntil('\n').toInt();
|
|
||||||
waitResponse();
|
|
||||||
return (res == 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+CIFSR"));
|
sendAT(GF("+CIFSR"));
|
||||||
String res;
|
String res;
|
||||||
if (waitResponse(10000L, res) != 1) {
|
if (waitResponse(10000L, 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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,
|
int rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",1"),
|
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",0"),
|
|
||||||
GFP(GSM_ERROR)) != 1)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
int rsp = waitResponse(60000L,
|
int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL),
|
||||||
GF(GSM_NL "+CIEV: \"SOUNDER\",0"),
|
GF(GSM_NL "NO ANSWER" GSM_NL));
|
||||||
GF(GSM_NL "+CIEV: \"CALL\",0"));
|
|
||||||
|
|
||||||
int 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, unsigned 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();
|
||||||
|
|
||||||
sendAT(GF("+VTS="), cmd);
|
sendAT(GF("+VTS="), cmd);
|
||||||
if (waitResponse(10000L) == 1) {
|
if (waitResponse(10000L) == 1) {
|
||||||
@@ -440,7 +334,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;
|
||||||
@@ -459,19 +353,15 @@ 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 ""; }
|
||||||
}
|
|
||||||
if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
stream.readStringUntil('"');
|
stream.readStringUntil('"');
|
||||||
String hex = stream.readStringUntil('"');
|
String hex = stream.readStringUntil('"');
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
@@ -486,38 +376,35 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sendSMS(const String& number, const String& text) {
|
|
||||||
sendAT(GF("+CMGF=1"));
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGS=\""), number, GF("\""));
|
|
||||||
if (waitResponse(GF(">")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
stream.print(text);
|
|
||||||
stream.write((char)0x1A);
|
|
||||||
stream.flush();
|
|
||||||
return waitResponse(60000L) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
// Note - the clock probably has to be set manaually first
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int8_t getBattPercentImpl() {
|
||||||
|
|
||||||
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();
|
int res = stream.readStringUntil('\n').toInt();
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
@@ -525,57 +412,37 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBattChargeState() {
|
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;
|
|
||||||
}
|
|
||||||
// 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();
|
chargeState = stream.readStringUntil(',').toInt();
|
||||||
percent = stream.readStringUntil('\n').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 getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client related functions
|
* Client related functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
|
||||||
|
int timeout_s = 75) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
|
|
||||||
protected:
|
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
||||||
|
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux, int timeout_s = 75) {
|
|
||||||
unsigned long startMillis = millis();
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
|
||||||
|
|
||||||
sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
|
||||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int newMux = stream.readStringUntil('\n').toInt();
|
int newMux = stream.readStringUntil('\n').toInt();
|
||||||
|
|
||||||
int rsp = waitResponse((timeout_ms- (millis() - startMillis)),
|
int rsp = waitResponse((timeout_ms - (millis() - startMillis)),
|
||||||
GF("CONNECT OK" GSM_NL),
|
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) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*mux = newMux;
|
*mux = newMux;
|
||||||
|
|
||||||
return (1 == rsp);
|
return (1 == rsp);
|
||||||
@@ -583,37 +450,38 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t modemRead(size_t, uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t modemGetAvailable(uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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\""));
|
int 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!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=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();
|
||||||
@@ -621,15 +489,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;
|
int 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();
|
int 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;
|
||||||
@@ -646,19 +514,19 @@ 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();
|
int mux = stream.readStringUntil(',').toInt();
|
||||||
int len = stream.readStringUntil(',').toInt();
|
int len = stream.readStringUntil(',').toInt();
|
||||||
int len_orig = len;
|
int 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:"))) {
|
||||||
@@ -671,38 +539,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTA6_H_
|
||||||
|
@@ -6,31 +6,23 @@
|
|||||||
* @date Apr 2018
|
* @date Apr 2018
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientBG96_h
|
#ifndef SRC_TINYGSMCLIENTBG96_H_
|
||||||
#define TinyGsmClientBG96_h
|
#define SRC_TINYGSMCLIENTBG96_H_
|
||||||
//#pragma message("TinyGSM: TinyGsmClientBG96")
|
// #pragma message("TinyGSM: TinyGsmClientBG96")
|
||||||
|
|
||||||
//#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 12
|
#define TINY_GSM_MUX_COUNT 12
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,474 +31,303 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmBG96
|
||||||
class TinyGsmBG96: public TinyGsmUTFSMS<TinyGsmBG96>
|
: public TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> {
|
||||||
{
|
friend class TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT>;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmBG96;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmBG96* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
|
||||||
prev_check = 0;
|
|
||||||
sock_connected = false;
|
|
||||||
got_data = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+QICLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { 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
|
* Inner Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientBG96 : public GsmClient {
|
||||||
|
friend class TinyGsmBG96;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GsmClientBG96() {}
|
||||||
|
|
||||||
|
explicit GsmClientBG96(TinyGsmBG96& modem, uint8_t mux = 1) {
|
||||||
|
init(&modem, mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(TinyGsmBG96* modem, uint8_t mux = 1) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_available = 0;
|
||||||
|
prev_check = 0;
|
||||||
|
sock_connected = false;
|
||||||
|
got_data = false;
|
||||||
|
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
|
at->sendAT(GF("+QICLOSE="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse();
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(15000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
/*
|
||||||
|
class GsmClientSecureBG96 : public GsmClientBG96
|
||||||
private:
|
|
||||||
TinyGsmBG96* at;
|
|
||||||
uint8_t mux;
|
|
||||||
uint16_t sock_available;
|
|
||||||
uint32_t prev_check;
|
|
||||||
bool sock_connected;
|
|
||||||
bool got_data;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// class GsmClientSecure : public GsmClient
|
|
||||||
// {
|
|
||||||
// public:
|
|
||||||
// GsmClientSecure() {}
|
|
||||||
//
|
|
||||||
// GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
|
|
||||||
// : 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:
|
|
||||||
|
|
||||||
TinyGsmBG96(Stream& stream)
|
|
||||||
: stream(stream)
|
|
||||||
{
|
{
|
||||||
|
public:
|
||||||
|
GsmClientSecure() {}
|
||||||
|
|
||||||
|
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
|
||||||
|
: public GsmClient(modem, mux)
|
||||||
|
{}
|
||||||
|
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
explicit TinyGsmBG96(Stream& stream) : stream(stream) {
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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("&FZ")); // Factory + Reset
|
|
||||||
// waitResponse();
|
|
||||||
|
|
||||||
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());
|
||||||
|
|
||||||
|
// Enable automatic time zone update
|
||||||
|
sendAT(GF("+CTZU=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
int ret = getSimStatus();
|
int 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 thisHasSSL() {
|
||||||
return "Quectel BG96";
|
return false; // TODO(?): Add SSL support
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
bool thisHasWifi() {
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
|
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CFUN=1,1"));
|
sendAT(GF("+CFUN=1,1"));
|
||||||
if (waitResponse(60000L, GF("POWERED DOWN")) != 1) {
|
if (waitResponse(60000L, GF("POWERED DOWN")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
waitResponse(5000L, GF("RDY"));
|
waitResponse(5000L, GF("RDY"));
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+QPOWD=1"));
|
sendAT(GF("+QPOWD=1"));
|
||||||
waitResponse(300); // returns OK first
|
waitResponse(300); // returns OK first
|
||||||
return waitResponse(300, GF("POWERED DOWN")) == 1;
|
return waitResponse(300, GF("POWERED 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.
|
||||||
delay(3000);
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
return true;
|
sendAT(GF("+QSCLK="), enable);
|
||||||
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
String getSimCCIDImpl() {
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+QCCID"));
|
sendAT(GF("+QCCID"));
|
||||||
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
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(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()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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();
|
||||||
|
|
||||||
//Configure the TCPIP Context
|
// Configure the TCPIP Context
|
||||||
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
|
||||||
if (waitResponse() != 1) {
|
GF("\""));
|
||||||
return false;
|
if (waitResponse() != 1) { return false; }
|
||||||
}
|
|
||||||
|
|
||||||
//Activate GPRS/CSD Context
|
// Activate GPRS/CSD Context
|
||||||
sendAT(GF("+QIACT=1"));
|
sendAT(GF("+QIACT=1"));
|
||||||
if (waitResponse(150000L) != 1) {
|
if (waitResponse(150000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//Attach to Packet Domain service - is this necessary?
|
// Attach to Packet Domain service - is this necessary?
|
||||||
sendAT(GF("+CGATT=1"));
|
sendAT(GF("+CGATT=1"));
|
||||||
if (waitResponse(60000L) != 1) {
|
if (waitResponse(60000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
sendAT(GF("+QIDEACT=1")); // Deactivate the bearer context
|
sendAT(GF("+QIDEACT=1")); // Deactivate the bearer context
|
||||||
if (waitResponse(40000L) != 1)
|
if (waitResponse(40000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
// Can follow all of the IP functions from the template
|
||||||
sendAT(GF("+CGPADDR=1"));
|
|
||||||
if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip context id
|
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
if (waitResponse() != 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
// Can follow all of the phone call functions from the template
|
||||||
|
|
||||||
bool callAnswer() {
|
|
||||||
sendAT(GF("A"));
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns true on pick-up, false on error/busy
|
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
bool callHangup() {
|
|
||||||
sendAT(GF("H"));
|
|
||||||
return waitResponse() == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 0-9,*,#,A,B,C,D
|
|
||||||
bool dtmfSend(char cmd, int duration_ms = 100) { // TODO: check
|
|
||||||
duration_ms = constrain(duration_ms, 100, 1000);
|
|
||||||
|
|
||||||
sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second
|
|
||||||
waitResponse();
|
|
||||||
|
|
||||||
sendAT(GF("+VTS="), cmd);
|
|
||||||
return waitResponse(10000L) == 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messaging functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
// Follows all messaging functions per template
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
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() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Client related functions
|
* Client related functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||||
|
bool ssl = false, int timeout_s = 20) {
|
||||||
|
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||||
|
int rsp;
|
||||||
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
|
|
||||||
protected:
|
// <PDPcontextID>(1-16), <connectID>(0-11),
|
||||||
|
// "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>",
|
||||||
|
// <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer)
|
||||||
|
sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
|
||||||
|
GF("\","), port, GF(",0,0"));
|
||||||
|
waitResponse();
|
||||||
|
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; }
|
||||||
bool ssl = false, int timeout_s = 20) {
|
|
||||||
if (ssl) {
|
|
||||||
DBG("SSL not yet supported on this module!");
|
|
||||||
}
|
|
||||||
int rsp;
|
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
|
||||||
|
|
||||||
// <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE",
|
if (stream.readStringUntil(',').toInt() != mux) { return false; }
|
||||||
// "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer)
|
|
||||||
sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
|
|
||||||
rsp = waitResponse();
|
|
||||||
|
|
||||||
if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream.readStringUntil(',').toInt() != mux) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Read status
|
// Read status
|
||||||
rsp = stream.readStringUntil('\n').toInt();
|
rsp = stream.readStringUntil('\n').toInt();
|
||||||
|
|
||||||
@@ -515,28 +336,20 @@ 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;
|
// TODO(?): Wait for ACK? AT+QISEND=id,0
|
||||||
}
|
|
||||||
// TODO: Wait for ACK? AT+QISEND=id,0
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t modemRead(size_t size, uint8_t mux) {
|
size_t modemRead(size_t size, uint8_t mux) {
|
||||||
sendAT(GF("+QIRD="), mux, ',', (uint16_t)size);
|
sendAT(GF("+QIRD="), mux, ',', (uint16_t)size);
|
||||||
if (waitResponse(GF("+QIRD:")) != 1) {
|
if (waitResponse(GF("+QIRD:")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
int len = stream.readStringUntil('\n').toInt();
|
int len = stream.readStringUntil('\n').toInt();
|
||||||
|
|
||||||
for (int i=0; i<len; i++) {
|
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
|
||||||
}
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
DBG("### READ:", len, "from", mux);
|
DBG("### READ:", len, "from", mux);
|
||||||
sockets[mux]->sock_available = modemGetAvailable(mux);
|
sockets[mux]->sock_available = modemGetAvailable(mux);
|
||||||
@@ -547,33 +360,28 @@ protected:
|
|||||||
sendAT(GF("+QIRD="), mux, GF(",0"));
|
sendAT(GF("+QIRD="), mux, GF(",0"));
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
if (waitResponse(GF("+QIRD:")) == 1) {
|
if (waitResponse(GF("+QIRD:")) == 1) {
|
||||||
streamSkipUntil(','); // Skip total received
|
streamSkipUntil(','); // Skip total received
|
||||||
streamSkipUntil(','); // Skip have read
|
streamSkipUntil(','); // Skip have read
|
||||||
result = stream.readStringUntil('\n').toInt();
|
result = stream.readStringUntil('\n').toInt();
|
||||||
if (result) {
|
if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); }
|
||||||
DBG("### DATA AVAILABLE:", result, "on", mux);
|
|
||||||
}
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
|
||||||
sockets[mux]->sock_connected = modemGetConnected(mux);
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
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:")) != 1)
|
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
|
int res = stream.readStringUntil(',').toInt(); // socket state
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -581,19 +389,16 @@ protected:
|
|||||||
return 2 == res;
|
return 2 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=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();
|
||||||
@@ -601,15 +406,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;
|
int 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();
|
int 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;
|
||||||
@@ -648,38 +453,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientBG96* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTBG96_H_
|
||||||
|
@@ -6,24 +6,21 @@
|
|||||||
* @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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
|
static unsigned 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,214 +35,187 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 6,
|
REG_UNKNOWN = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmESP8266
|
class TinyGsmESP8266
|
||||||
{
|
: public TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||||
|
friend class TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmESP8266;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_connected = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse(maxWaitMs);
|
|
||||||
rx.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { stop(5000L); }
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Inner Client
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientESP8266 : public GsmClient {
|
||||||
|
friend class TinyGsmESP8266;
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
public:
|
||||||
|
GsmClientESP8266() {}
|
||||||
|
|
||||||
private:
|
explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
||||||
TinyGsmESP8266* at;
|
init(&modem, mux);
|
||||||
uint8_t mux;
|
}
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_connected = false;
|
||||||
|
|
||||||
class GsmClientSecure : public GsmClient
|
at->sockets[mux] = this;
|
||||||
{
|
|
||||||
public:
|
|
||||||
GsmClientSecure() {}
|
|
||||||
|
|
||||||
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
|
return true;
|
||||||
: GsmClient(modem, mux)
|
}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual ~GsmClientSecure() {}
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
void stop(uint32_t maxWaitMs) {
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
TINY_GSM_YIELD();
|
||||||
stop();
|
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||||
TINY_GSM_YIELD();
|
sock_connected = false;
|
||||||
rx.clear();
|
at->waitResponse(maxWaitMs);
|
||||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
rx.clear();
|
||||||
return sock_connected;
|
}
|
||||||
}
|
void stop() override {
|
||||||
};
|
stop(5000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
public:
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
TinyGsmESP8266(Stream& stream)
|
/*
|
||||||
: stream(stream)
|
* Inner Secure Client
|
||||||
{
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientSecureESP8266 : public GsmClientESP8266 {
|
||||||
|
public:
|
||||||
|
GsmClientSecureESP8266() {}
|
||||||
|
|
||||||
|
explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1)
|
||||||
|
: GsmClientESP8266(modem, mux) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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() {
|
bool thisHasSSL() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWifi() {
|
bool thisHasWifi() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return false;
|
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
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
// SIM card functions don't apply
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generic network functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
RegStatus getRegistrationStatus() {
|
RegStatus getRegistrationStatus() {
|
||||||
sendAT(GF("+CIPSTATUS"));
|
sendAT(GF("+CIPSTATUS"));
|
||||||
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
|
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
|
||||||
@@ -255,52 +225,44 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|||||||
return (RegStatus)status;
|
return (RegStatus)status;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
protected:
|
||||||
* Generic network functions
|
int16_t getSignalQualityImpl() {
|
||||||
*/
|
|
||||||
|
|
||||||
int16_t getSignalQuality() {
|
|
||||||
sendAT(GF("+CWJAP_CUR?"));
|
sendAT(GF("+CWJAP_CUR?"));
|
||||||
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
|
||||||
if (res1 != 2) {
|
if (res1 != 2) {
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
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
|
int 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()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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;
|
||||||
@@ -309,7 +271,7 @@ 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"));
|
||||||
@@ -319,74 +281,107 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
|||||||
/*
|
/*
|
||||||
* IP Address functions
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+CIPSTA_CUR??"));
|
sendAT(GF("+CIPSTA_CUR?"));
|
||||||
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
|
||||||
if (res1 != 2) {
|
if (res1 != 2) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res2 = stream.readStringUntil('"');
|
String res2 = stream.readStringUntil('"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res2;
|
return res2;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
/*
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
* Phone Call functions
|
||||||
}
|
*/
|
||||||
|
protected:
|
||||||
|
bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool
|
||||||
|
dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Messaging functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool sendSMSImpl(const String& number,
|
||||||
|
const String& text) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool sendSMS_UTF16Impl(const char* const number, const void* text,
|
||||||
|
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Location functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
String
|
||||||
|
getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
float getTemperatureImpl() 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),
|
int 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t modemRead(size_t, uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t modemGetAvailable(uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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 =
|
int status =
|
||||||
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
|
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
|
||||||
if (status != 3) {
|
if (status != 3) {
|
||||||
@@ -399,14 +394,15 @@ 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();
|
int returned_mux = stream.readStringUntil(',').toInt();
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
streamSkipUntil(','); // Skip type
|
streamSkipUntil(','); // Skip 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
|
||||||
streamSkipUntil('\n'); // Skip client/server type
|
streamSkipUntil('\n'); // Skip client/server type
|
||||||
verified_connections[returned_mux] = 1;
|
verified_connections[returned_mux] = 1;
|
||||||
}
|
}
|
||||||
@@ -418,19 +414,16 @@ protected:
|
|||||||
return verified_connections[mux];
|
return verified_connections[mux];
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=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();
|
||||||
@@ -438,15 +431,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;
|
int 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();
|
int 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;
|
||||||
@@ -463,25 +456,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();
|
int mux = stream.readStringUntil(',').toInt();
|
||||||
int len = stream.readStringUntil(':').toInt();
|
int len = stream.readStringUntil(':').toInt();
|
||||||
int len_orig = len;
|
int 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));
|
int muxStart =
|
||||||
|
TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
|
||||||
int coma = data.indexOf(',', muxStart);
|
int coma = data.indexOf(',', muxStart);
|
||||||
int mux = data.substring(muxStart, coma).toInt();
|
int 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;
|
||||||
}
|
}
|
||||||
@@ -490,38 +485,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTESP8266_H_
|
||||||
|
@@ -6,31 +6,23 @@
|
|||||||
* @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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,110 +31,89 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmM590
|
class TinyGsmM590
|
||||||
{
|
: public TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||||
|
friend class TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmM590;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_connected = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, timeout_s);
|
|
||||||
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
at->sendAT(GF("+TCPCLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse(maxWaitMs);
|
|
||||||
rx.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { stop(1000L); }
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_WRITE()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extended API
|
* Inner Client
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientM590 : public GsmClient {
|
||||||
|
friend class TinyGsmM590;
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
public:
|
||||||
|
GsmClientM590() {}
|
||||||
|
|
||||||
private:
|
explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 1) {
|
||||||
TinyGsmM590* at;
|
init(&modem, mux);
|
||||||
uint8_t mux;
|
}
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_connected = false;
|
||||||
|
|
||||||
public:
|
at->sockets[mux] = this;
|
||||||
|
|
||||||
TinyGsmM590(Stream& stream)
|
return true;
|
||||||
: stream(stream)
|
}
|
||||||
{
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
at->sendAT(GF("+TCPCLOSE="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse(maxWaitMs);
|
||||||
|
rx.clear();
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(1000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
explicit TinyGsmM590(Stream& stream) : stream(stream) {
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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("&FZ")); // Factory + Reset
|
|
||||||
// waitResponse();
|
|
||||||
|
|
||||||
sendAT(GF("E0")); // 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
|
||||||
@@ -158,76 +129,63 @@ public:
|
|||||||
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
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
|
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+XISP=0")); // Use internal stack
|
sendAT(GF("+XISP=0")); // Use internal stack
|
||||||
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 thisHasSSL() {
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWifi() {
|
bool thisHasWifi() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
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;
|
||||||
}
|
}
|
||||||
@@ -235,54 +193,29 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
|||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
// Able to follow all SIM card functions as inherited from the template
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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"));
|
||||||
@@ -292,44 +225,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
if (!user) user = "";
|
if (!user) user = "";
|
||||||
if (!pwd) pwd = "";
|
if (!pwd) pwd = "";
|
||||||
sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
|
sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
delay(500);
|
delay(500);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// set_dns: // TODO
|
// set_dns: // TODO
|
||||||
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
|
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
//
|
//
|
||||||
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
|
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
int res = stream.readStringUntil(',').toInt();
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res == 1;
|
return res == 1;
|
||||||
@@ -338,12 +269,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
/*
|
/*
|
||||||
* IP Address functions
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+XIIC?"));
|
sendAT(GF("+XIIC?"));
|
||||||
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
@@ -351,103 +280,64 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
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 callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
|
bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
dtmfSendImpl(char cmd, int duration_ms = 100) 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
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type available
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
float getTemperatureImpl() 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,
|
||||||
|
int timeout_s = 75) {
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux, 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,
|
int rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL), GF(",FAIL" GSM_NL),
|
||||||
GF(",OK" GSM_NL),
|
GF("+TCPSETUP:Error" GSM_NL));
|
||||||
GF(",FAIL" GSM_NL),
|
|
||||||
GF("+TCPSETUP:Error" GSM_NL));
|
|
||||||
if (1 == rsp) {
|
if (1 == rsp) {
|
||||||
return true;
|
return true;
|
||||||
} else if (3 == rsp) {
|
} else if (3 == rsp) {
|
||||||
@@ -461,50 +351,49 @@ 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;
|
|
||||||
}
|
|
||||||
stream.readStringUntil('\n');
|
stream.readStringUntil('\n');
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t modemRead(size_t, uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
size_t modemGetAvailable(uint8_t) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
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\""));
|
int 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!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=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();
|
||||||
@@ -512,15 +401,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;
|
int 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();
|
int 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;
|
||||||
@@ -537,19 +426,19 @@ 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();
|
int mux = stream.readStringUntil(',').toInt();
|
||||||
int len = stream.readStringUntil(',').toInt();
|
int len = stream.readStringUntil(',').toInt();
|
||||||
int len_orig = len;
|
int 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:"))) {
|
||||||
@@ -563,38 +452,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTM590_H_
|
||||||
|
@@ -2,35 +2,28 @@
|
|||||||
* @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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,132 +32,120 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmM95
|
||||||
class TinyGsmM95: public TinyGsmUTFSMS<TinyGsmM95>
|
: public TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT> {
|
||||||
{
|
friend class TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT>;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmM95;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmM95* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
|
||||||
sock_connected = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+QICLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* Inner Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientM95 : public GsmClient {
|
||||||
|
friend class TinyGsmM95;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GsmClientM95() {}
|
||||||
|
|
||||||
|
explicit GsmClientM95(TinyGsmM95& modem, uint8_t mux = 1) {
|
||||||
|
init(&modem, mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(TinyGsmM95* modem, uint8_t mux = 1) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_available = 0;
|
||||||
|
sock_connected = false;
|
||||||
|
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
|
at->sendAT(GF("+QICLOSE="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
|
||||||
|
GF("CLOSE OK"), GF("ERROR"));
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(75000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
/*
|
||||||
|
class GsmClientSecureM95 : public GsmClientM95
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GsmClientSecure() {}
|
||||||
|
|
||||||
private:
|
GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
|
||||||
TinyGsmM95* at;
|
: GsmClient(modem, mux)
|
||||||
uint8_t mux;
|
{}
|
||||||
uint16_t sock_available;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// class GsmClientSecure : public GsmClient
|
public:
|
||||||
// {
|
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||||
// public:
|
stop();
|
||||||
// GsmClientSecure() {}
|
TINY_GSM_YIELD();
|
||||||
//
|
rx.clear();
|
||||||
// GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
// : GsmClient(modem, mux)
|
return sock_connected;
|
||||||
// {}
|
}
|
||||||
//
|
};
|
||||||
// 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:
|
* Constructor
|
||||||
|
*/
|
||||||
TinyGsmM95(Stream& stream)
|
public:
|
||||||
: stream(stream)
|
explicit TinyGsmM95(Stream& stream) : stream(stream) {
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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("&FZ")); // Factory + Reset
|
// sendAT(GF("&FZ")); // Factory + Reset
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
|
|
||||||
sendAT(GF("E0")); // 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
|
||||||
@@ -175,62 +156,43 @@ public:
|
|||||||
|
|
||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
|
// Enable network time synchronization
|
||||||
|
sendAT(GF("+QNITZ=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
int ret = getSimStatus();
|
int 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 thisHasSSL() {
|
||||||
return "Quectel M95";
|
return false; // TODO(?): Add SSL support
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
bool thisHasWifi() {
|
||||||
|
|
||||||
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
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"));
|
||||||
@@ -240,77 +202,51 @@ 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.
|
||||||
delay(3000);
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
return true;
|
sendAT(GF("+QSCLK="), enable);
|
||||||
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
String getSimCCIDImpl() {
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+QCCID"));
|
sendAT(GF("+QCCID"));
|
||||||
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setHostFormat( bool useDottedQuad ) {
|
public:
|
||||||
if ( useDottedQuad ) {
|
void setHostFormat(bool useDottedQuad) {
|
||||||
|
if (useDottedQuad) {
|
||||||
sendAT(GF("+QIDNSIP=0"));
|
sendAT(GF("+QIDNSIP=0"));
|
||||||
} else {
|
} else {
|
||||||
sendAT(GF("+QIDNSIP=1"));
|
sendAT(GF("+QIDNSIP=1"));
|
||||||
@@ -318,63 +254,47 @@ TINY_GSM_MODEM_GET_CSQ()
|
|||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
// 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):"
|
||||||
@@ -390,7 +310,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) {
|
||||||
@@ -407,18 +328,16 @@ 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
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+QILOCIP"));
|
sendAT(GF("+QILOCIP"));
|
||||||
stream.readStringUntil('\n');
|
stream.readStringUntil('\n');
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
@@ -426,147 +345,59 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete all SMS */
|
/** Delete all SMS */
|
||||||
bool deleteAllSMS() {
|
bool deleteAllSMS() {
|
||||||
sendAT(GF("+QMGDA=6"));
|
sendAT(GF("+QMGDA=6"));
|
||||||
if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
|
if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Phone Call functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Location functions
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & 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 = stream.readStringUntil(',').toInt();
|
||||||
streamSkipUntil(','); // Skip thermistor charge
|
streamSkipUntil(','); // Skip thermistor charge
|
||||||
float temp = stream.readStringUntil('\n').toFloat();
|
float temp = stream.readStringUntil('\n').toFloat();
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
waitResponse();
|
waitResponse();
|
||||||
@@ -576,33 +407,25 @@ 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 ssl = false, int timeout_s = 75) {
|
||||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||||
bool ssl = false, int timeout_s = 75) {
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
if (ssl) {
|
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
|
||||||
DBG("SSL not yet supported on this module!");
|
GF("\","), port);
|
||||||
}
|
int rsp =
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
|
||||||
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port);
|
GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
|
||||||
int rsp = waitResponse(timeout_ms,
|
return (1 == rsp);
|
||||||
GF("CONNECT OK" GSM_NL),
|
|
||||||
GF("CONNECT FAIL" GSM_NL),
|
|
||||||
GF("ALREADY CONNECT" GSM_NL));
|
|
||||||
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("+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;
|
||||||
@@ -621,11 +444,11 @@ protected:
|
|||||||
// }
|
// }
|
||||||
// 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
|
||||||
@@ -641,40 +464,43 @@ protected:
|
|||||||
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 = stream.readStringUntil('\n').toInt();
|
||||||
// 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++) {
|
moveCharFromStreamToFifo(mux);
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
|
||||||
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;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
int res = stream.readStringUntil(',').toInt(); // socket state
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -682,19 +508,16 @@ protected:
|
|||||||
return 2 == res;
|
return 2 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=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 +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;
|
int 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();
|
int 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;
|
||||||
@@ -738,9 +561,9 @@ 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);
|
int nl = data.lastIndexOf(GSM_NL, data.length() - 8);
|
||||||
int coma = data.indexOf(',', nl+2);
|
int coma = data.indexOf(',', nl + 2);
|
||||||
int mux = data.substring(nl+2, coma).toInt();
|
int 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;
|
||||||
}
|
}
|
||||||
@@ -749,38 +572,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTM95_H_
|
||||||
|
@@ -9,32 +9,23 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientMC60_h
|
#ifndef SRC_TINYGSMCLIENTMC60_H_
|
||||||
#define TinyGsmClientMC60_h
|
#define SRC_TINYGSMCLIENTMC60_H_
|
||||||
//#pragma message("TinyGSM: TinyGsmClientMC60")
|
// #pragma message("TinyGSM: TinyGsmClientMC60")
|
||||||
|
|
||||||
//#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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
SIM_READY = 1,
|
|
||||||
SIM_LOCKED = 2,
|
|
||||||
SIM_ANTITHEFT_LOCKED = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
||||||
@@ -43,178 +34,150 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class TinyGsmMC60
|
||||||
class TinyGsmMC60: public TinyGsmUTFSMS<TinyGsmMC60>
|
: public TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT> {
|
||||||
{
|
friend class TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT>;
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmMC60;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmMC60* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
|
||||||
sock_connected = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+QICLOSE="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* Inner Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientMC60 : public GsmClient {
|
||||||
|
friend class TinyGsmMC60;
|
||||||
|
|
||||||
|
public:
|
||||||
|
GsmClientMC60() {}
|
||||||
|
|
||||||
|
explicit GsmClientMC60(TinyGsmMC60& modem, uint8_t mux = 1) {
|
||||||
|
init(&modem, mux);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init(TinyGsmMC60* modem, uint8_t mux = 1) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_available = 0;
|
||||||
|
sock_connected = false;
|
||||||
|
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
uint32_t startMillis = millis();
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
|
at->sendAT(GF("+QICLOSE="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
|
||||||
|
GF("CLOSE OK"), GF("ERROR"));
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(75000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
*/
|
*/
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
/*
|
||||||
|
class GsmClientSecureMC60 : public GsmClientMC60
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GsmClientSecure() {}
|
||||||
|
|
||||||
private:
|
GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
|
||||||
TinyGsmMC60* at;
|
: GsmClient(modem, mux)
|
||||||
uint8_t mux;
|
{}
|
||||||
uint16_t sock_available;
|
|
||||||
bool sock_connected;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// class GsmClientSecure : public GsmClient
|
public:
|
||||||
// {
|
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||||
// public:
|
stop();
|
||||||
// GsmClientSecure() {}
|
TINY_GSM_YIELD();
|
||||||
//
|
rx.clear();
|
||||||
// GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
// : GsmClient(modem, mux)
|
return sock_connected;
|
||||||
// {}
|
}
|
||||||
//
|
};
|
||||||
// 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:
|
* Constructor
|
||||||
|
*/
|
||||||
TinyGsmMC60(Stream& stream)
|
public:
|
||||||
: stream(stream)
|
explicit TinyGsmMC60(Stream& stream) : stream(stream) {
|
||||||
{
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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("&FZ")); // Factory + Reset
|
// sendAT(GF("&FZ")); // Factory + Reset
|
||||||
// waitResponse();
|
// waitResponse();
|
||||||
|
|
||||||
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());
|
||||||
|
|
||||||
|
// Enable network time synchronization
|
||||||
|
sendAT(GF("+QNITZ=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
int ret = getSimStatus();
|
int 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() {
|
|
||||||
#if defined(TINY_GSM_MODEM_MC60)
|
|
||||||
return "Quectel MC60";
|
|
||||||
#elif defined(TINY_GSM_MODEM_MC60E)
|
|
||||||
return "Quectel MC60E";
|
|
||||||
#endif
|
|
||||||
return "Quectel MC60";
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* under development
|
* under development
|
||||||
*/
|
*/
|
||||||
// bool hasSSL() {
|
// bool thisHasSSL() {
|
||||||
// sendAT(GF("+QIPSSL=?"));
|
// sendAT(GF("+QIPSSL=?"));
|
||||||
// if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
|
// if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
|
||||||
// return false;
|
// return false;
|
||||||
@@ -222,125 +185,106 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
|||||||
// return waitResponse() == 1;
|
// return waitResponse() == 1;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
bool hasSSL() {
|
bool thisHasSSL() {
|
||||||
return false; // TODO: For now
|
return false; // TODO(?): Add SSL support
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWifi() {
|
bool thisHasWifi() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
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) != 1) {
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CFUN=1,1"));
|
sendAT(GF("+CFUN=1,1"));
|
||||||
if (waitResponse(10000L) != 1) {
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
delay(3000);
|
delay(3000);
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+QPOWD=1"));
|
sendAT(GF("+QPOWD=1"));
|
||||||
return waitResponse(GF("NORMAL POWER DOWN")) == 1;
|
return waitResponse(GF("NORMAL POWER DOWN")) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() {
|
// When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
|
||||||
if (!testAT()) {
|
// is pulled up, the module can directly enter into sleep mode.If entering
|
||||||
return false;
|
// into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled
|
||||||
}
|
// down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first,
|
||||||
sendAT(GF("+CFUN=0"));
|
// and then the module can enter into sleep mode.
|
||||||
if (waitResponse(10000L) != 1) {
|
bool sleepEnableImpl(bool enable = true) {
|
||||||
return false;
|
sendAT(GF("+QSCLK="), enable);
|
||||||
}
|
return waitResponse() == 1;
|
||||||
delay(3000);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) {
|
||||||
|
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
|
||||||
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?"));
|
sendAT(GF("+CPIN?"));
|
||||||
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
|
||||||
delay(1000);
|
delay(1000);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK"));
|
int status =
|
||||||
|
waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"),
|
||||||
|
GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
switch (status) {
|
switch (status) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3: return SIM_LOCKED;
|
case 3: return SIM_LOCKED;
|
||||||
case 5:
|
case 5:
|
||||||
case 6: return SIM_ANTITHEFT_LOCKED;
|
case 6: return SIM_ANTITHEFT_LOCKED;
|
||||||
case 1: return SIM_READY;
|
case 1: return SIM_READY;
|
||||||
default: return SIM_ERROR;
|
default: return SIM_ERROR;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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; }
|
||||||
}
|
|
||||||
|
|
||||||
//Define PDP context - is this necessary?
|
// Define PDP context - is this necessary?
|
||||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -350,56 +294,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
|
|
||||||
// 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=2 - Output a notification statement:
|
// Mode=2 - Output a notification statement:
|
||||||
// “+QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>”
|
// “+QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>”
|
||||||
sendAT(GF("+QINDI=2"));
|
sendAT(GF("+QINDI=2"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+QILOCIP"));
|
sendAT(GF("+QILOCIP"));
|
||||||
stream.readStringUntil('\n');
|
stream.readStringUntil('\n');
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
@@ -407,61 +337,23 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Delete all SMS */
|
/** Delete all SMS */
|
||||||
bool deleteAllSMS() {
|
bool deleteAllSMS() {
|
||||||
sendAT(GF("+QMGDA=6"));
|
sendAT(GF("+QMGDA=6"));
|
||||||
if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) {
|
if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -470,118 +362,60 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|||||||
/*
|
/*
|
||||||
* Location functions
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
// Can use CIPGSMLOC as inherited from the template
|
||||||
|
|
||||||
String getGsmLocation() {
|
/*
|
||||||
sendAT(GF("+CIPGSMLOC=1,1"));
|
* GPS location functions
|
||||||
if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
|
*/
|
||||||
return "";
|
public:
|
||||||
}
|
// No functions of this type supported
|
||||||
String res = stream.readStringUntil('\n');
|
|
||||||
waitResponse();
|
/*
|
||||||
res.trim();
|
* Time functions
|
||||||
return res;
|
*/
|
||||||
}
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
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() 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) {
|
||||||
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;
|
||||||
}
|
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host,
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
GF("\","), port);
|
||||||
sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port);
|
int rsp =
|
||||||
int rsp = waitResponse(timeout_ms,
|
waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL),
|
||||||
GF("CONNECT OK" GSM_NL),
|
GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL));
|
||||||
GF("CONNECT FAIL" GSM_NL),
|
|
||||||
GF("ALREADY CONNECT" GSM_NL));
|
|
||||||
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("+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;
|
||||||
while ( !allAcknowledged ) {
|
while (!allAcknowledged) {
|
||||||
sendAT( GF("+QISACK"));
|
sendAT(GF("+QISACK"));
|
||||||
if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
|
if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
streamSkipUntil(','); /** Skip total */
|
streamSkipUntil(','); /** Skip total */
|
||||||
streamSkipUntil(','); /** Skip acknowledged data size */
|
streamSkipUntil(','); /** Skip acknowledged data size */
|
||||||
if ( stream.readStringUntil('\n').toInt() == 0 ) {
|
if (stream.readStringUntil('\n').toInt() == 0) {
|
||||||
allAcknowledged = true;
|
allAcknowledged = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -591,16 +425,16 @@ protected:
|
|||||||
// streamSkipUntil(','); // Skip mux
|
// streamSkipUntil(','); // Skip mux
|
||||||
// return stream.readStringUntil('\n').toInt();
|
// return stream.readStringUntil('\n').toInt();
|
||||||
|
|
||||||
return len; // TODO
|
return len; // TODO(?): verify len/ack
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = roll in connection - 1, client of connection
|
// sc = role in connection = 1, client of connection
|
||||||
// sid = index of connection - mux
|
// sid = index of connection = mux
|
||||||
// len = maximum length of data to send
|
// len = maximum length of data to retrieve
|
||||||
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.
|
||||||
@@ -615,36 +449,38 @@ protected:
|
|||||||
// This is quite likely if the buffer is broken into packets - which may
|
// This is quite likely if the buffer is broken into packets - which may
|
||||||
// be different sizes.
|
// be different sizes.
|
||||||
// If so, make sure we make sure we re-set the amount of data available.
|
// If so, make sure we make sure we re-set the amount of data available.
|
||||||
if (len < size) {
|
if (len < size) { sockets[mux]->sock_available = len; }
|
||||||
sockets[mux]->sock_available = len;
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
}
|
moveCharFromStreamToFifo(mux);
|
||||||
for (uint16_t i=0; i<len; i++) {
|
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
|
||||||
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();
|
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;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
int res = stream.readStringUntil(',').toInt(); // socket state
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
@@ -652,19 +488,16 @@ protected:
|
|||||||
return 2 == res;
|
return 2 == res;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
|
GsmConstStr r5 = NULL, GsmConstStr r6 = 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();
|
||||||
@@ -673,15 +506,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
String r6s(r6); r6s.trim();
|
String r6s(r6); r6s.trim();
|
||||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
|
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
|
||||||
data.reserve(64);
|
data.reserve(64);
|
||||||
int index = 0;
|
int 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();
|
int 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;
|
||||||
@@ -700,7 +533,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
} else if (r6 && data.endsWith(r6)) {
|
} else if (r6 && data.endsWith(r6)) {
|
||||||
index = 6;
|
index = 6;
|
||||||
goto finish;
|
goto finish;
|
||||||
} else if (data.endsWith(GF(GSM_NL "+QIRD:"))) { // TODO: QIRD? or QIRDI?
|
} else if (data.endsWith(
|
||||||
|
GF(GSM_NL "+QIRD:"))) { // TODO(?): QIRD? or QIRDI?
|
||||||
// +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>
|
// +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>
|
||||||
streamSkipUntil(','); // Skip the context
|
streamSkipUntil(','); // Skip the context
|
||||||
streamSkipUntil(','); // Skip the role
|
streamSkipUntil(','); // Skip the role
|
||||||
@@ -711,14 +545,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
// read the length of the current packet
|
// read the length of the current packet
|
||||||
int len_packet = stream.readStringUntil('\n').toInt();
|
int len_packet = stream.readStringUntil('\n').toInt();
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||||
sockets[mux]->sock_available = len_packet*num_packets;
|
sockets[mux]->sock_available = len_packet * num_packets;
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
DBG("### Got Data:", len, "on", mux);
|
DBG("### Got Data:", len_packet * num_packets, "on", mux);
|
||||||
} 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);
|
int nl = data.lastIndexOf(GSM_NL, data.length() - 8);
|
||||||
int coma = data.indexOf(',', nl+2);
|
int coma = data.indexOf(',', nl + 2);
|
||||||
int mux = data.substring(nl+2, coma).toInt();
|
int 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;
|
||||||
}
|
}
|
||||||
@@ -727,38 +561,37 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_t
|
||||||
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) {
|
||||||
String data;
|
String data;
|
||||||
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6);
|
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
|
uint8_t
|
||||||
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5, r6);
|
return waitResponse(1000, r1, r2, r3, r4, r5, r6);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientMC60* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTMC60_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
@@ -6,34 +6,26 @@
|
|||||||
* @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>
|
||||||
|
|
||||||
|
class TinyGsmSim808 : public TinyGsmSim800 {
|
||||||
class TinyGsmSim808: public TinyGsmSim800
|
public:
|
||||||
{
|
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
TinyGsmSim808(Stream& stream)
|
|
||||||
: TinyGsmSim800(stream)
|
|
||||||
{}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPS location functions
|
* GPS location functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
// enable GPS
|
// enable GPS
|
||||||
bool enableGPS() {
|
bool enableGPS() {
|
||||||
// uint16_t state;
|
// uint16_t state;
|
||||||
|
|
||||||
sendAT(GF("+CGNSPWR=1"));
|
sendAT(GF("+CGNSPWR=1"));
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -42,9 +34,7 @@ public:
|
|||||||
// uint16_t state;
|
// 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;
|
||||||
}
|
}
|
||||||
@@ -53,9 +43,7 @@ public:
|
|||||||
// works only with ans SIM808 V2
|
// works only with ans SIM808 V2
|
||||||
String getGPSraw() {
|
String getGPSraw() {
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
@@ -64,23 +52,22 @@ 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 getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0,
|
||||||
//String buffer = "";
|
int* vsat = 0, int* usat = 0) {
|
||||||
|
// String buffer = "";
|
||||||
// char chr_buffer[12];
|
// char chr_buffer[12];
|
||||||
bool fix = false;
|
bool fix = false;
|
||||||
|
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.readStringUntil(','); // mode
|
stream.readStringUntil(','); // mode
|
||||||
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true;
|
if (stream.readStringUntil(',').toInt() == 1) fix = true;
|
||||||
stream.readStringUntil(','); //utctime
|
stream.readStringUntil(','); // utctime
|
||||||
*lat = stream.readStringUntil(',').toFloat(); //lat
|
*lat = stream.readStringUntil(',').toFloat(); // lat
|
||||||
*lon = stream.readStringUntil(',').toFloat(); //lon
|
*lon = stream.readStringUntil(',').toFloat(); // lon
|
||||||
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon
|
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // lon
|
||||||
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed
|
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
@@ -88,8 +75,10 @@ public:
|
|||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
stream.readStringUntil(',');
|
stream.readStringUntil(',');
|
||||||
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
|
if (vsat != NULL)
|
||||||
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites
|
*vsat = stream.readStringUntil(',').toInt(); // viewed satelites
|
||||||
|
if (usat != NULL)
|
||||||
|
*usat = stream.readStringUntil(',').toInt(); // used satelites
|
||||||
stream.readStringUntil('\n');
|
stream.readStringUntil('\n');
|
||||||
|
|
||||||
waitResponse();
|
waitResponse();
|
||||||
@@ -99,34 +88,31 @@ public:
|
|||||||
|
|
||||||
// get GPS time
|
// get GPS time
|
||||||
// works only with SIM808 V2
|
// works only with SIM808 V2
|
||||||
bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) {
|
bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute,
|
||||||
|
int* second) {
|
||||||
bool fix = false;
|
bool fix = false;
|
||||||
char chr_buffer[12];
|
char chr_buffer[12];
|
||||||
sendAT(GF("+CGNSINF"));
|
sendAT(GF("+CGNSINF"));
|
||||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
String buffer = stream.readStringUntil(',');
|
String buffer = stream.readStringUntil(',');
|
||||||
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
|
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
|
||||||
switch (i) {
|
switch (i) {
|
||||||
case 0:
|
case 0:
|
||||||
//mode
|
// mode
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
//fixstatus
|
// fixstatus
|
||||||
if ( buffer.toInt() == 1 ) {
|
if (buffer.toInt() == 1) { fix = buffer.toInt(); }
|
||||||
fix = buffer.toInt();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
*year = buffer.substring(0,4).toInt();
|
*year = buffer.substring(0, 4).toInt();
|
||||||
*month = buffer.substring(4,6).toInt();
|
*month = buffer.substring(4, 6).toInt();
|
||||||
*day = buffer.substring(6,8).toInt();
|
*day = buffer.substring(6, 8).toInt();
|
||||||
*hour = buffer.substring(8,10).toInt();
|
*hour = buffer.substring(8, 10).toInt();
|
||||||
*minute = buffer.substring(10,12).toInt();
|
*minute = buffer.substring(10, 12).toInt();
|
||||||
*second = buffer.substring(12,14).toInt();
|
*second = buffer.substring(12, 14).toInt();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -135,7 +121,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
String res = stream.readStringUntil('\n');
|
stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
if (fix) {
|
if (fix) {
|
||||||
@@ -144,7 +130,6 @@ public:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTSIM808_H_
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,30 +6,22 @@
|
|||||||
* @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
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,156 +40,144 @@ enum SocketStatus {
|
|||||||
SOCK_OPENING = 6,
|
SOCK_OPENING = 6,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmSequansMonarch
|
class TinyGsmSequansMonarch
|
||||||
{
|
: public TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
|
||||||
|
TINY_GSM_MUX_COUNT> {
|
||||||
public:
|
friend class TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
|
||||||
|
TINY_GSM_MUX_COUNT>;
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmSequansMonarch;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient() {}
|
|
||||||
|
|
||||||
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
|
||||||
prev_check = 0;
|
|
||||||
sock_connected = false;
|
|
||||||
got_data = false;
|
|
||||||
|
|
||||||
// adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
|
|
||||||
// using modulus will force 6 back to 0
|
|
||||||
at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
|
||||||
if (sock_connected) stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+SQNSH="), mux);
|
|
||||||
sock_connected = false;
|
|
||||||
at->waitResponse();
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { 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
|
* Inner Client
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientSequansMonarch : public GsmClient {
|
||||||
|
friend class TinyGsmSequansMonarch;
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
public:
|
||||||
|
GsmClientSequansMonarch() {}
|
||||||
|
|
||||||
private:
|
explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||||
TinyGsmSequansMonarch* at;
|
uint8_t mux = 1) {
|
||||||
uint8_t mux;
|
init(&modem, mux);
|
||||||
uint16_t sock_available;
|
}
|
||||||
uint32_t prev_check;
|
|
||||||
bool sock_connected;
|
|
||||||
bool got_data;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
class GsmClientSecure : public GsmClient {
|
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
|
||||||
public:
|
this->at = modem;
|
||||||
GsmClientSecure() {}
|
this->mux = mux;
|
||||||
|
sock_available = 0;
|
||||||
|
prev_check = 0;
|
||||||
|
sock_connected = false;
|
||||||
|
got_data = false;
|
||||||
|
|
||||||
GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1)
|
// adjust for zero indexed socket array vs Sequans' 1 indexed mux numbers
|
||||||
: GsmClient(modem, mux)
|
// using modulus will force 6 back to 0
|
||||||
{}
|
at->sockets[mux % TINY_GSM_MUX_COUNT] = this;
|
||||||
|
|
||||||
virtual ~GsmClientSecure() {}
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
if (sock_connected) stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
|
at->sendAT(GF("+SQNSH="), mux);
|
||||||
|
sock_connected = false;
|
||||||
|
at->waitResponse();
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(15000L);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch {
|
||||||
|
public:
|
||||||
|
GsmClientSecureSequansMonarch() {}
|
||||||
|
|
||||||
|
explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||||
|
uint8_t mux = 1)
|
||||||
|
: GsmClientSequansMonarch(modem, mux) {}
|
||||||
|
|
||||||
|
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) {
|
||||||
stop();
|
stop();
|
||||||
TINY_GSM_YIELD();
|
TINY_GSM_YIELD();
|
||||||
rx.clear();
|
rx.clear();
|
||||||
|
|
||||||
// configure security profile 1 with parameters:
|
// configure security profile 1 with parameters:
|
||||||
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
|
// verify server certificate against imported CA certs 0 and enforce
|
||||||
// validity period (3)
|
// 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)
|
||||||
// support wider variety of cipher suites
|
// support wider variety of cipher suites
|
||||||
// do not verify server certificate (0)
|
// do not verify server certificate (0)
|
||||||
at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\""));
|
at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\""));
|
||||||
}
|
}
|
||||||
if (at->waitResponse() != 1) {
|
if (at->waitResponse() != 1) {
|
||||||
DBG("failed to configure security profile");
|
DBG("failed to configure security profile");
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||||
|
return sock_connected;
|
||||||
}
|
}
|
||||||
|
|
||||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
void setStrictSSL(bool strict) {
|
||||||
return sock_connected;
|
strictSSL = strict;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
void setStrictSSL(bool strict) {
|
/*
|
||||||
strictSSL = strict;
|
* Constructor
|
||||||
}
|
*/
|
||||||
|
public:
|
||||||
};
|
explicit TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
|
||||||
|
|
||||||
public:
|
|
||||||
TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
|
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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
|
#ifdef TINY_GSM_DEBUG
|
||||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
@@ -209,133 +189,87 @@ public:
|
|||||||
DBG(GF("### Modem:"), getModemName());
|
DBG(GF("### Modem:"), getModemName());
|
||||||
|
|
||||||
// Make sure the module is enabled. Unlike others, the VZN20Q powers on
|
// 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
|
// with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full
|
||||||
// The module cannot even detect the sim card if the cellular functionality is disabled so
|
// functionality The module cannot even detect the sim card if the cellular
|
||||||
// unless we explicitly enable the functionality the init will fail.
|
// functionality is disabled so unless we explicitly enable the
|
||||||
|
// functionality the init will fail.
|
||||||
sendAT(GF("+CFUN=1"));
|
sendAT(GF("+CFUN=1"));
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
|
// Enable automatic time zome update
|
||||||
|
sendAT(GF("+CTZU=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
int ret = getSimStatus();
|
int 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() {
|
void maintainImpl() {
|
||||||
// return "Sequans Monarch";
|
|
||||||
sendAT(GF("+CGMI"));
|
|
||||||
String res1;
|
|
||||||
if (waitResponse(1000L, res1) != 1) {
|
|
||||||
return "u-blox Cellular Modem";
|
|
||||||
}
|
|
||||||
res1.replace(GSM_NL "OK" GSM_NL, "");
|
|
||||||
res1.trim();
|
|
||||||
|
|
||||||
sendAT(GF("+CGMM"));
|
|
||||||
String res2;
|
|
||||||
if (waitResponse(1000L, res2) != 1) {
|
|
||||||
return "u-blox Cellular Modem";
|
|
||||||
}
|
|
||||||
res2.replace(GSM_NL "OK" GSM_NL, "");
|
|
||||||
res2.trim();
|
|
||||||
|
|
||||||
String name = res1 + String(' ') + res2;
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
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);
|
||||||
// modemGetConnected() always checks the state of ALL socks
|
// modemGetConnected() always checks the state of ALL socks
|
||||||
modemGetConnected();
|
modemGetConnected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (stream.available()) {
|
while (stream.available()) { waitResponse(15, NULL, NULL); }
|
||||||
waitResponse(15, NULL, NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool factoryDefault() {
|
bool thisHasGPRS() {
|
||||||
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
|
return true;
|
||||||
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 thisHasWifi() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool hasSSL() {
|
bool thisHasSSL() {
|
||||||
return true;
|
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")) ;
|
int res =
|
||||||
if (res != 1 && res != 3) {
|
waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), 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;
|
||||||
}
|
}
|
||||||
@@ -343,68 +277,36 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
|||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
String getSimCCIDImpl() {
|
||||||
|
|
||||||
String getSimCCID() {
|
|
||||||
sendAT(GF("+SQNCCID"));
|
sendAT(GF("+SQNCCID"));
|
||||||
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
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:
|
||||||
TINY_GSM_MODEM_GET_CSQ()
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CEREG");
|
||||||
bool isNetworkConnected() {
|
|
||||||
RegStatus s = getRegistrationStatus();
|
|
||||||
if (s == REG_OK_HOME || s == REG_OK_ROAMING) {
|
|
||||||
// DBG(F("connected with status:"), s);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
protected:
|
||||||
|
bool isNetworkConnectedImpl() {
|
||||||
|
RegStatus s = getRegistrationStatus();
|
||||||
|
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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!)
|
||||||
@@ -423,123 +325,89 @@ 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
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+CGPADDR=3"));
|
sendAT(GF("+CGPADDR=3"));
|
||||||
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) {
|
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\"');
|
String res = stream.readStringUntil('\"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
IPAddress localIP() {
|
|
||||||
return TinyGsmIpFromString(getLocalIP());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Phone Call functions
|
* Phone Call functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool
|
||||||
|
dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* Messaging functions
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
*/
|
||||||
|
protected:
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
// Follows all messaging functions per template
|
||||||
|
|
||||||
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
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
|
uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
float getTemperatureImpl() {
|
||||||
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() {
|
|
||||||
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) {
|
||||||
int rsp;
|
int rsp;
|
||||||
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;
|
||||||
|
|
||||||
if (ssl) {
|
if (ssl) {
|
||||||
// enable SSl and use security profile 1
|
// enable SSl and use security profile 1
|
||||||
@@ -552,24 +420,28 @@ 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);
|
||||||
|
|
||||||
@@ -578,20 +450,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;
|
||||||
@@ -602,7 +474,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!");
|
||||||
@@ -611,7 +482,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");
|
||||||
@@ -630,8 +501,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");
|
||||||
@@ -642,12 +513,9 @@ 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();
|
int len = stream.readStringUntil('\n').toInt();
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
@@ -670,9 +538,9 @@ protected:
|
|||||||
sendAT(GF("+SQNSI="), mux);
|
sendAT(GF("+SQNSI="), mux);
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
if (waitResponse(GF("+SQNSI:")) == 1) {
|
if (waitResponse(GF("+SQNSI:")) == 1) {
|
||||||
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 = stream.readStringUntil(',').toInt(); // keep data not yet read
|
||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
@@ -685,9 +553,7 @@ 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 (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no
|
||||||
// DBG("### Warning: misaligned mux numbers!");
|
// DBG("### Warning: misaligned mux numbers!");
|
||||||
@@ -704,26 +570,24 @@ 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!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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 r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
GsmConstStr r5 = 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();
|
||||||
@@ -731,15 +595,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;
|
int 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();
|
int 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;
|
||||||
@@ -760,7 +624,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
int len = stream.readStringUntil('\n').toInt();
|
int len = stream.readStringUntil('\n').toInt();
|
||||||
if (mux >= 0 && 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]) {
|
||||||
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 = "";
|
||||||
@@ -776,12 +640,10 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
@@ -790,23 +652,24 @@ finish:
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
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),
|
uint8_t
|
||||||
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||||
|
@@ -6,32 +6,23 @@
|
|||||||
* @date Nov 2016
|
* @date Nov 2016
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef TinyGsmClientUBLOX_h
|
#ifndef SRC_TINYGSMCLIENTUBLOX_H_
|
||||||
#define TinyGsmClientUBLOX_h
|
#define SRC_TINYGSMCLIENTUBLOX_H_
|
||||||
//#pragma message("TinyGSM: TinyGsmClientUBLOX")
|
// #pragma message("TinyGSM: TinyGsmClientUBLOX")
|
||||||
|
|
||||||
//#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 7
|
#define TINY_GSM_MUX_COUNT 7
|
||||||
|
|
||||||
#include <TinyGsmCommon.h>
|
#include "TinyGsmCommon.h"
|
||||||
|
|
||||||
#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 const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
|
||||||
|
|
||||||
enum SimStatus {
|
|
||||||
SIM_ERROR = 0,
|
|
||||||
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,
|
||||||
@@ -40,127 +31,115 @@ enum RegStatus {
|
|||||||
REG_UNKNOWN = 4,
|
REG_UNKNOWN = 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class TinyGsmUBLOX
|
class TinyGsmUBLOX
|
||||||
{
|
: public TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> {
|
||||||
|
friend class TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE,
|
||||||
public:
|
TINY_GSM_MUX_COUNT>;
|
||||||
|
|
||||||
class GsmClient : public Client
|
|
||||||
{
|
|
||||||
friend class TinyGsmUBLOX;
|
|
||||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
|
||||||
|
|
||||||
public:
|
|
||||||
GsmClient() {}
|
|
||||||
|
|
||||||
GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) {
|
|
||||||
init(&modem, mux);
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual ~GsmClient(){}
|
|
||||||
|
|
||||||
bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) {
|
|
||||||
this->at = modem;
|
|
||||||
this->mux = mux;
|
|
||||||
sock_available = 0;
|
|
||||||
prev_check = 0;
|
|
||||||
sock_connected = false;
|
|
||||||
got_data = false;
|
|
||||||
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
|
||||||
stop();
|
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
|
|
||||||
uint8_t oldMux = mux;
|
|
||||||
sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
|
|
||||||
if (mux != oldMux) {
|
|
||||||
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
|
|
||||||
at->sockets[oldMux] = NULL;
|
|
||||||
}
|
|
||||||
at->sockets[mux] = this;
|
|
||||||
at->maintain();
|
|
||||||
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
|
||||||
|
|
||||||
virtual void stop(uint32_t maxWaitMs) {
|
|
||||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
|
||||||
at->sendAT(GF("+USOCL="), mux);
|
|
||||||
at->waitResponse(); // should return within 1s
|
|
||||||
sock_connected = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
virtual void stop() { 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
|
* Inner Client
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientUBLOX : public GsmClient {
|
||||||
|
friend class TinyGsmUBLOX;
|
||||||
|
|
||||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
public:
|
||||||
|
GsmClientUBLOX() {}
|
||||||
|
|
||||||
private:
|
explicit GsmClientUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0) {
|
||||||
TinyGsmUBLOX* at;
|
init(&modem, mux);
|
||||||
uint8_t mux;
|
}
|
||||||
uint16_t sock_available;
|
|
||||||
uint32_t prev_check;
|
|
||||||
bool sock_connected;
|
|
||||||
bool got_data;
|
|
||||||
RxFifo rx;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) {
|
||||||
|
this->at = modem;
|
||||||
|
this->mux = mux;
|
||||||
|
sock_available = 0;
|
||||||
|
prev_check = 0;
|
||||||
|
sock_connected = false;
|
||||||
|
got_data = false;
|
||||||
|
|
||||||
class GsmClientSecure : public GsmClient
|
at->sockets[mux] = this;
|
||||||
{
|
|
||||||
public:
|
|
||||||
GsmClientSecure() {}
|
|
||||||
|
|
||||||
GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1)
|
return true;
|
||||||
: GsmClient(modem, mux)
|
}
|
||||||
{}
|
|
||||||
|
|
||||||
virtual ~GsmClientSecure(){}
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
|
||||||
public:
|
uint8_t oldMux = mux;
|
||||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
sock_connected = at->modemConnect(host, port, &mux, false, timeout_s);
|
||||||
stop();
|
if (mux != oldMux) {
|
||||||
TINY_GSM_YIELD();
|
|
||||||
rx.clear();
|
|
||||||
uint8_t oldMux = mux;
|
|
||||||
sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
|
|
||||||
if (mux != oldMux) {
|
|
||||||
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
|
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
|
||||||
at->sockets[oldMux] = NULL;
|
at->sockets[oldMux] = NULL;
|
||||||
|
}
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
at->maintain();
|
||||||
|
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
at->sockets[mux] = this;
|
|
||||||
at->maintain();
|
|
||||||
return sock_connected;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
void stop(uint32_t maxWaitMs) {
|
||||||
|
dumpModemBuffer(maxWaitMs);
|
||||||
|
at->sendAT(GF("+USOCL="), mux);
|
||||||
|
at->waitResponse(); // should return within 1s
|
||||||
|
sock_connected = false;
|
||||||
|
}
|
||||||
|
void stop() override {
|
||||||
|
stop(15000L);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
/*
|
||||||
|
* Extended API
|
||||||
|
*/
|
||||||
|
|
||||||
TinyGsmUBLOX(Stream& stream)
|
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
: stream(stream)
|
};
|
||||||
{
|
|
||||||
|
/*
|
||||||
|
* Inner Secure Client
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
class GsmClientSecureUBLOX : public GsmClientUBLOX {
|
||||||
|
public:
|
||||||
|
GsmClientSecureUBLOX() {}
|
||||||
|
|
||||||
|
explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 1)
|
||||||
|
: GsmClientUBLOX(modem, mux) {}
|
||||||
|
|
||||||
|
public:
|
||||||
|
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||||
|
stop();
|
||||||
|
TINY_GSM_YIELD();
|
||||||
|
rx.clear();
|
||||||
|
uint8_t oldMux = mux;
|
||||||
|
sock_connected = at->modemConnect(host, port, &mux, true, timeout_s);
|
||||||
|
if (mux != oldMux) {
|
||||||
|
DBG("WARNING: Mux number changed from", oldMux, "to", mux);
|
||||||
|
at->sockets[oldMux] = NULL;
|
||||||
|
}
|
||||||
|
at->sockets[mux] = this;
|
||||||
|
at->maintain();
|
||||||
|
return sock_connected;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Constructor
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
explicit TinyGsmUBLOX(Stream& stream) : stream(stream) {
|
||||||
memset(sockets, 0, sizeof(sockets));
|
memset(sockets, 0, sizeof(sockets));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,21 +147,13 @@ public:
|
|||||||
* Basic functions
|
* Basic functions
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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
|
#ifdef TINY_GSM_DEBUG
|
||||||
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
sendAT(GF("+CMEE=2")); // turn on verbose error codes
|
||||||
@@ -193,176 +164,127 @@ public:
|
|||||||
|
|
||||||
getModemName();
|
getModemName();
|
||||||
|
|
||||||
|
// Enable automatic time zome update
|
||||||
|
sendAT(GF("+CTZU=1"));
|
||||||
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
|
|
||||||
int ret = getSimStatus();
|
int 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 true
|
// if the sim is ready, or it's locked but no pin has been provided,
|
||||||
else {
|
// return true
|
||||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String getModemName() {
|
String getModemNameImpl() {
|
||||||
sendAT(GF("+CGMI"));
|
sendAT(GF("+CGMI"));
|
||||||
String res1;
|
String res1;
|
||||||
if (waitResponse(1000L, res1) != 1) {
|
if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; }
|
||||||
return "u-blox Cellular Modem";
|
|
||||||
}
|
|
||||||
res1.replace(GSM_NL "OK" GSM_NL, "");
|
res1.replace(GSM_NL "OK" GSM_NL, "");
|
||||||
res1.trim();
|
res1.trim();
|
||||||
|
|
||||||
sendAT(GF("+GMM"));
|
sendAT(GF("+GMM"));
|
||||||
String res2;
|
String res2;
|
||||||
if (waitResponse(1000L, res2) != 1) {
|
if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; }
|
||||||
return "u-blox Cellular Modem";
|
|
||||||
}
|
|
||||||
res2.replace(GSM_NL "OK" GSM_NL, "");
|
res2.replace(GSM_NL "OK" GSM_NL, "");
|
||||||
res2.trim();
|
res2.trim();
|
||||||
|
|
||||||
String name = res1 + String(' ') + res2;
|
String name = res1 + String(' ') + res2;
|
||||||
DBG("### Modem:", name);
|
DBG("### Modem:", name);
|
||||||
if (name.startsWith("u-blox SARA-R4") || name.startsWith("u-blox SARA-N4")) {
|
if (name.startsWith("u-blox SARA-R4") ||
|
||||||
|
name.startsWith("u-blox SARA-N4")) {
|
||||||
DBG("### WARNING: You are using the wrong TinyGSM modem!");
|
DBG("### WARNING: You are using the wrong TinyGSM modem!");
|
||||||
}
|
} else if (name.startsWith("u-blox SARA-N2")) {
|
||||||
else if (name.startsWith("u-blox SARA-N2")) {
|
|
||||||
DBG("### SARA N2 NB-IoT modems not supported!");
|
DBG("### SARA N2 NB-IoT modems not supported!");
|
||||||
}
|
}
|
||||||
|
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
bool factoryDefaultImpl() {
|
||||||
|
|
||||||
TINY_GSM_MODEM_TEST_AT()
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
|
|
||||||
|
|
||||||
bool factoryDefault() {
|
|
||||||
sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM
|
sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM
|
||||||
waitResponse();
|
waitResponse();
|
||||||
sendAT(GF("+CFUN=16")); // Reset
|
sendAT(GF("+CFUN=16")); // Reset
|
||||||
return waitResponse() == 1;
|
return waitResponse() == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
bool thisHasSSL() {
|
||||||
|
|
||||||
bool hasSSL() {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasWifi() {
|
bool thisHasWifi() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasGPRS() {
|
bool thisHasGPRS() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Power functions
|
* Power functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
bool restart() {
|
bool restartImpl() {
|
||||||
if (!testAT()) {
|
if (!testAT()) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
sendAT(GF("+CFUN=16"));
|
sendAT(GF("+CFUN=16"));
|
||||||
if (waitResponse(10000L) != 1) {
|
if (waitResponse(10000L) != 1) { return false; }
|
||||||
return false;
|
delay(3000); // TODO(?): Verify delay timing here
|
||||||
}
|
|
||||||
delay(3000); // TODO: Verify delay timing here
|
|
||||||
return init();
|
return init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool poweroff() {
|
bool powerOffImpl() {
|
||||||
sendAT(GF("+CPWROFF"));
|
sendAT(GF("+CPWROFF"));
|
||||||
return waitResponse(40000L) == 1;
|
return waitResponse(40000L) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool radioOff() {
|
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
sendAT(GF("+CFUN=0"));
|
|
||||||
if (waitResponse(10000L) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
delay(3000);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SIM card functions
|
* SIM card functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
String getIMEIImpl() {
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_SIMCCID_CCID()
|
|
||||||
|
|
||||||
String getIMEI() {
|
|
||||||
sendAT(GF("+CGSN"));
|
sendAT(GF("+CGSN"));
|
||||||
if (waitResponse(GF(GSM_NL)) != 1) {
|
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
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(CGREG)
|
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_OPERATOR_COPS()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generic network functions
|
* Generic network functions
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
|
RegStatus getRegistrationStatus() {
|
||||||
|
return (RegStatus)getRegistrationStatusXREG("CGREG");
|
||||||
|
}
|
||||||
|
|
||||||
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)
|
if (s == REG_OK_HOME || s == REG_OK_ROAMING)
|
||||||
return true;
|
return true;
|
||||||
else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
|
else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
|
||||||
return isGprsConnected();
|
return isGprsConnected();
|
||||||
else return false;
|
else
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
||||||
|
|
||||||
sendAT(GF("+CGATT=1")); // attach to GPRS
|
sendAT(GF("+CGATT=1")); // attach to GPRS
|
||||||
if (waitResponse(360000L) != 1) {
|
if (waitResponse(360000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting up the PSD profile/PDP context with the UPSD commands sets up an
|
// Setting up the PSD profile/PDP context with the UPSD commands sets up an
|
||||||
// "internal" PDP context, i.e. a data connection using the internal IP
|
// "internal" PDP context, i.e. a data connection using the internal IP
|
||||||
@@ -388,15 +310,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP on PSD profile 0
|
sendAT(GF("+UPSD=0,7,\"0.0.0.0\"")); // Dynamic IP on PSD profile 0
|
||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
// Packet switched data action
|
// Packet switched data action
|
||||||
// AT+UPSDA=<profile_id>,<action>
|
// AT+UPSDA=<profile_id>,<action>
|
||||||
// profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context)
|
// profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context)
|
||||||
// action = 3: activate; it activates a PDP context with the specified profile,
|
// action = 3: activate; it activates a PDP context with the specified
|
||||||
// using the current parameters
|
// profile, using the current parameters
|
||||||
sendAT(GF("+UPSDA=0,3")); // Activate the PDP context associated with profile 0
|
sendAT(GF(
|
||||||
|
"+UPSDA=0,3")); // Activate the PDP context associated with profile 0
|
||||||
if (waitResponse(360000L) != 1) { // Should return ok
|
if (waitResponse(360000L) != 1) { // Should return ok
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -406,12 +329,13 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
// for the active PDP context associated with the specified PSD profile.
|
// for the active PDP context associated with the specified PSD profile.
|
||||||
// AT+UPSND=<profile_id>,<param_tag>
|
// AT+UPSND=<profile_id>,<param_tag>
|
||||||
// profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context)
|
// profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context)
|
||||||
// param_tag = 8: PSD profile status: if the profile is active the return value is 1, 0 otherwise
|
// param_tag = 8: PSD profile status: if the profile is active the return
|
||||||
sendAT(GF("+UPSND=0,8")); // Check if PSD profile 0 is now active
|
// value is 1, 0 otherwise
|
||||||
|
sendAT(GF("+UPSND=0,8")); // Check if PSD profile 0 is now active
|
||||||
int res = waitResponse(GF(",8,1"), GF(",8,0"));
|
int res = waitResponse(GF(",8,1"), GF(",8,0"));
|
||||||
waitResponse(); // Should return another OK
|
waitResponse(); // Should return another OK
|
||||||
if (res == 1) {
|
if (res == 1) {
|
||||||
return true; // It's now active
|
return true; // It's now active
|
||||||
} else if (res == 2) { // If it's not active yet, wait for the +UUPSDA URC
|
} else if (res == 2) { // If it's not active yet, wait for the +UUPSDA URC
|
||||||
if (waitResponse(180000L, GF("+UUPSDA: 0")) != 1) { // 0=successful
|
if (waitResponse(180000L, GF("+UUPSDA: 0")) != 1) { // 0=successful
|
||||||
return false;
|
return false;
|
||||||
@@ -424,138 +348,109 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool gprsDisconnect() {
|
bool gprsDisconnectImpl() {
|
||||||
sendAT(GF("+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
|
sendAT(GF(
|
||||||
if (waitResponse(360000L) != 1) {
|
"+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
|
||||||
return false;
|
if (waitResponse(360000L) != 1) { return false; }
|
||||||
}
|
|
||||||
|
|
||||||
sendAT(GF("+CGATT=0")); // detach from GPRS
|
sendAT(GF("+CGATT=0")); // detach from GPRS
|
||||||
if (waitResponse(360000L) != 1) {
|
if (waitResponse(360000L) != 1) { return false; }
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IP Address functions
|
* IP Address functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getLocalIP() {
|
String getLocalIPImpl() {
|
||||||
sendAT(GF("+UPSND=0,0"));
|
sendAT(GF("+UPSND=0,0"));
|
||||||
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; }
|
||||||
return "";
|
streamSkipUntil(','); // Skip PSD profile
|
||||||
}
|
streamSkipUntil('\"'); // Skip request type
|
||||||
streamSkipUntil(','); // Skip PSD profile
|
|
||||||
streamSkipUntil('\"'); // Skip request type
|
|
||||||
String res = stream.readStringUntil('\"');
|
String res = stream.readStringUntil('\"');
|
||||||
if (waitResponse() != 1) {
|
if (waitResponse() != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
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;
|
// Can follow all of the phone call functions from the template
|
||||||
|
|
||||||
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Messaging functions
|
* Messaging functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
// Can follow all template functions
|
||||||
|
|
||||||
bool sendSMS(const String& number, const String& text) {
|
|
||||||
sendAT(GF("+CSCS=\"GSM\"")); // Set GSM default alphabet
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGF=1")); // Set preferred message format to text mode
|
|
||||||
waitResponse();
|
|
||||||
sendAT(GF("+CMGS=\""), number, GF("\"")); // set the phone number
|
|
||||||
if (waitResponse(GF(">")) != 1) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
stream.print(text); // Actually send the message
|
|
||||||
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
|
* Location functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
String getGsmLocation() {
|
String getGsmLocationImpl() {
|
||||||
sendAT(GF("+ULOC=2,3,0,120,1"));
|
sendAT(GF("+ULOC=2,3,0,120,1"));
|
||||||
if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) {
|
if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; }
|
||||||
return "";
|
|
||||||
}
|
|
||||||
String res = stream.readStringUntil('\n');
|
String res = stream.readStringUntil('\n');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
res.trim();
|
res.trim();
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* GPS location functions
|
||||||
|
*/
|
||||||
|
public:
|
||||||
|
// No functions of this type supported
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time functions
|
||||||
|
*/
|
||||||
|
protected:
|
||||||
|
// Can follow the standard CCLK function in the template
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Battery & temperature functions
|
* Battery & temperature functions
|
||||||
*/
|
*/
|
||||||
|
protected:
|
||||||
|
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
int8_t getBattPercentImpl() {
|
||||||
|
|
||||||
int8_t getBattPercent() {
|
|
||||||
sendAT(GF("+CIND?"));
|
sendAT(GF("+CIND?"));
|
||||||
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int res = stream.readStringUntil(',').toInt();
|
int res = stream.readStringUntil(',').toInt();
|
||||||
int8_t percent = res*20; // return is 0-5
|
int8_t percent = res * 20; // return is 0-5
|
||||||
// Wait for final OK
|
// Wait for final OK
|
||||||
waitResponse();
|
waitResponse();
|
||||||
return percent;
|
return percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||||
|
|
||||||
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) {
|
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||||
|
uint16_t& milliVolts) {
|
||||||
chargeState = 0;
|
chargeState = 0;
|
||||||
percent = getBattPercent();
|
percent = getBattPercent();
|
||||||
milliVolts = 0;
|
milliVolts = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This would only available for a small number of modules in this group (TOBY-L)
|
// This would only available for a small number of modules in this group
|
||||||
float getTemperature() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
// (TOBY-L)
|
||||||
|
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 = 120)
|
bool ssl = false, int timeout_s = 120) {
|
||||||
{
|
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||||
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
|
|
||||||
sendAT(GF("+USOCR=6")); // create a socket
|
sendAT(GF("+USOCR=6")); // create a socket
|
||||||
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { // reply is +USOCR: ## of socket created
|
if (waitResponse(GF(GSM_NL "+USOCR:")) !=
|
||||||
|
1) { // reply is +USOCR: ## of socket created
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*mux = stream.readStringUntil('\n').toInt();
|
*mux = stream.readStringUntil('\n').toInt();
|
||||||
@@ -571,8 +466,8 @@ protected:
|
|||||||
waitResponse();
|
waitResponse();
|
||||||
|
|
||||||
// Enable KEEPALIVE, 30 sec
|
// Enable KEEPALIVE, 30 sec
|
||||||
//sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
|
// sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
|
||||||
//waitResponse();
|
// waitResponse();
|
||||||
|
|
||||||
// connect on the allocated socket
|
// connect on the allocated socket
|
||||||
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
|
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
|
||||||
@@ -582,17 +477,13 @@ 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("+USOWR="), mux, ',', (uint16_t)len);
|
sendAT(GF("+USOWR="), mux, ',', (uint16_t)len);
|
||||||
if (waitResponse(GF("@")) != 1) {
|
if (waitResponse(GF("@")) != 1) { return 0; }
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// 50ms delay, see AT manual section 25.10.4
|
// 50ms delay, see AT manual section 25.10.4
|
||||||
delay(50);
|
delay(50);
|
||||||
stream.write((uint8_t*)buff, len);
|
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
|
||||||
stream.flush();
|
stream.flush();
|
||||||
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; }
|
||||||
return 0;
|
streamSkipUntil(','); // Skip mux
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip mux
|
|
||||||
int sent = stream.readStringUntil('\n').toInt();
|
int sent = stream.readStringUntil('\n').toInt();
|
||||||
waitResponse(); // sends back OK after the confirmation of number sent
|
waitResponse(); // sends back OK after the confirmation of number sent
|
||||||
return sent;
|
return sent;
|
||||||
@@ -600,16 +491,12 @@ protected:
|
|||||||
|
|
||||||
size_t modemRead(size_t size, uint8_t mux) {
|
size_t modemRead(size_t size, uint8_t mux) {
|
||||||
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
|
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
|
||||||
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
|
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; }
|
||||||
return 0;
|
streamSkipUntil(','); // Skip mux
|
||||||
}
|
|
||||||
streamSkipUntil(','); // Skip mux
|
|
||||||
int len = stream.readStringUntil(',').toInt();
|
int len = stream.readStringUntil(',').toInt();
|
||||||
streamSkipUntil('\"');
|
streamSkipUntil('\"');
|
||||||
|
|
||||||
for (int i=0; i<len; i++) {
|
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
|
||||||
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
|
|
||||||
}
|
|
||||||
streamSkipUntil('\"');
|
streamSkipUntil('\"');
|
||||||
waitResponse();
|
waitResponse();
|
||||||
DBG("### READ:", len, "from", mux);
|
DBG("### READ:", len, "from", mux);
|
||||||
@@ -620,19 +507,17 @@ protected:
|
|||||||
size_t modemGetAvailable(uint8_t mux) {
|
size_t modemGetAvailable(uint8_t mux) {
|
||||||
// NOTE: Querying a closed socket gives an error "operation not allowed"
|
// NOTE: Querying a closed socket gives an error "operation not allowed"
|
||||||
sendAT(GF("+USORD="), mux, ",0");
|
sendAT(GF("+USORD="), mux, ",0");
|
||||||
size_t result = 0;
|
size_t result = 0;
|
||||||
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
|
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
|
||||||
// Will give error "operation not allowed" when attempting to read a socket
|
// Will give error "operation not allowed" when attempting to read a socket
|
||||||
// that you have already told to close
|
// that you have already told to close
|
||||||
if (res == 1) {
|
if (res == 1) {
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
result = stream.readStringUntil('\n').toInt();
|
result = stream.readStringUntil('\n').toInt();
|
||||||
// if (result) DBG("### DATA AVAILABLE:", result, "on", mux);
|
// if (result) DBG("### DATA AVAILABLE:", result, "on", mux);
|
||||||
waitResponse();
|
waitResponse();
|
||||||
}
|
}
|
||||||
if (!result) {
|
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
|
||||||
sockets[mux]->sock_connected = modemGetConnected(mux);
|
|
||||||
}
|
|
||||||
DBG("### AVAILABLE:", result, "on", mux);
|
DBG("### AVAILABLE:", result, "on", mux);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -641,11 +526,10 @@ protected:
|
|||||||
// NOTE: Querying a closed socket gives an error "operation not allowed"
|
// NOTE: Querying a closed socket gives an error "operation not allowed"
|
||||||
sendAT(GF("+USOCTL="), mux, ",10");
|
sendAT(GF("+USOCTL="), mux, ",10");
|
||||||
uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
|
uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
|
||||||
if (res != 1)
|
if (res != 1) { return false; }
|
||||||
return false;
|
|
||||||
|
|
||||||
streamSkipUntil(','); // Skip mux
|
streamSkipUntil(','); // Skip mux
|
||||||
streamSkipUntil(','); // Skip type
|
streamSkipUntil(','); // Skip type
|
||||||
int result = stream.readStringUntil('\n').toInt();
|
int result = stream.readStringUntil('\n').toInt();
|
||||||
// 0: the socket is in INACTIVE status (it corresponds to CLOSED status
|
// 0: the socket is in INACTIVE status (it corresponds to CLOSED status
|
||||||
// defined in RFC793 "TCP Protocol Specification" [112])
|
// defined in RFC793 "TCP Protocol Specification" [112])
|
||||||
@@ -663,19 +547,16 @@ protected:
|
|||||||
return (result != 0);
|
return (result != 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Utilities
|
* Utilities
|
||||||
*/
|
*/
|
||||||
|
public:
|
||||||
TINY_GSM_MODEM_STREAM_UTILITIES()
|
// TODO(vshymanskyy): Optimize this!
|
||||||
|
uint8_t
|
||||||
// TODO: Optimize this!
|
waitResponse(uint32_t timeout_ms, String& data, 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),
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=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();
|
||||||
@@ -683,15 +564,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;
|
int 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();
|
int 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;
|
||||||
@@ -714,7 +595,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
int mux = stream.readStringUntil(',').toInt();
|
int mux = stream.readStringUntil(',').toInt();
|
||||||
int len = stream.readStringUntil('\n').toInt();
|
int len = stream.readStringUntil('\n').toInt();
|
||||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||||
sockets[mux]->got_data = true;
|
sockets[mux]->got_data = true;
|
||||||
sockets[mux]->sock_available = len;
|
sockets[mux]->sock_available = len;
|
||||||
}
|
}
|
||||||
data = "";
|
data = "";
|
||||||
@@ -729,38 +610,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} 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, "/");
|
||||||
//DBG('<', index, '>', data);
|
// DBG('<', index, '>', data);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t waitResponse(uint32_t timeout_ms,
|
uint8_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=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||||
{
|
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),
|
uint8_t
|
||||||
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
|
waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR),
|
||||||
{
|
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
|
||||||
|
GsmConstStr r5 = NULL) {
|
||||||
return waitResponse(1000, r1, r2, r3, r4, r5);
|
return waitResponse(1000, r1, r2, r3, r4, r5);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
protected:
|
||||||
Stream& stream;
|
Stream& stream;
|
||||||
|
GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT];
|
||||||
protected:
|
const char* gsmNL = GSM_NL;
|
||||||
GsmClient* sockets[TINY_GSM_MUX_COUNT];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SRC_TINYGSMCLIENTUBLOX_H_
|
||||||
|
File diff suppressed because it is too large
Load Diff
1710
src/TinyGsmCommon.h
1710
src/TinyGsmCommon.h
File diff suppressed because it is too large
Load Diff
@@ -25,23 +25,35 @@ void setup() {
|
|||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
|
|
||||||
// Test the start/restart functions
|
// Test the basic functions
|
||||||
modem.restart();
|
modem.init();
|
||||||
modem.begin();
|
modem.begin();
|
||||||
|
modem.setBaud(115200);
|
||||||
modem.testAT();
|
modem.testAT();
|
||||||
modem.factoryDefault();
|
modem.factoryDefault();
|
||||||
|
modem.getModemInfo();
|
||||||
|
modem.getModemName();
|
||||||
|
modem.maintain();
|
||||||
|
modem.hasSSL();
|
||||||
|
modem.hasWifi();
|
||||||
|
modem.hasGPRS();
|
||||||
|
|
||||||
|
// Test Power functions
|
||||||
|
modem.restart();
|
||||||
|
// modem.sleepEnable();
|
||||||
|
modem.radioOff();
|
||||||
|
modem.poweroff();
|
||||||
|
|
||||||
// Test the SIM card functions
|
// Test the SIM card functions
|
||||||
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
#if defined(TINY_GSM_MODEM_HAS_GPRS)
|
||||||
modem.getSimCCID();
|
modem.getSimCCID();
|
||||||
modem.getIMEI();
|
modem.getIMEI();
|
||||||
modem.getSimStatus();
|
modem.getSimStatus();
|
||||||
modem.getRegistrationStatus();
|
|
||||||
modem.getOperator();
|
modem.getOperator();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// Test the Networking functions
|
// Test the Networking functions
|
||||||
|
modem.getRegistrationStatus();
|
||||||
modem.getSignalQuality();
|
modem.getSignalQuality();
|
||||||
modem.localIP();
|
modem.localIP();
|
||||||
|
|
||||||
@@ -61,7 +73,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();
|
||||||
@@ -77,4 +89,9 @@ void loop() {
|
|||||||
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
#if defined(TINY_GSM_MODEM_HAS_WIFI)
|
||||||
modem.networkDisconnect();
|
modem.networkDisconnect();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Test battery and temperature functions
|
||||||
|
// modem.getBattVoltage();
|
||||||
|
// modem.getBattPercent();
|
||||||
|
// modem.getTemperature();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user