Browse Source

CRTP!!!! Totally untested

Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
v_master
Sara Damiano 5 years ago
parent
commit
d3d1083d8f
31 changed files with 5226 additions and 6661 deletions
  1. +110
    -0
      .clang-format
  2. +1
    -0
      .gitignore
  3. +3
    -0
      cpplint.cfg
  4. +3
    -3
      examples/AllFunctions/AllFunctions.ino
  5. +1
    -1
      examples/BlynkClient/BlynkClient.ino
  6. +6
    -6
      examples/FileDownload/FileDownload.ino
  7. +3
    -3
      examples/HttpClient/HttpClient.ino
  8. +3
    -3
      examples/HttpsClient/HttpsClient.ino
  9. +4
    -4
      examples/MqttClient/MqttClient.ino
  10. +4
    -4
      examples/WebClient/WebClient.ino
  11. +4
    -4
      examples/more/Hologram_Dash/Hologram_Dash.ino
  12. +3
    -3
      examples/more/Industruino/Industruino.ino
  13. +1
    -1
      examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino
  14. +87
    -88
      src/TinyGsmClient.h
  15. +227
    -361
      src/TinyGsmClientA6.h
  16. +228
    -425
      src/TinyGsmClientBG96.h
  17. +241
    -248
      src/TinyGsmClientESP8266.h
  18. +201
    -314
      src/TinyGsmClientM590.h
  19. +250
    -429
      src/TinyGsmClientM95.h
  20. +268
    -435
      src/TinyGsmClientMC60.h
  21. +259
    -412
      src/TinyGsmClientSIM5360.h
  22. +279
    -556
      src/TinyGsmClientSIM7000.h
  23. +268
    -421
      src/TinyGsmClientSIM7600.h
  24. +271
    -579
      src/TinyGsmClientSIM800.h
  25. +40
    -55
      src/TinyGsmClientSIM808.h
  26. +267
    -422
      src/TinyGsmClientSaraR4.h
  27. +264
    -401
      src/TinyGsmClientSequansMonarch.h
  28. +241
    -362
      src/TinyGsmClientUBLOX.h
  29. +565
    -510
      src/TinyGsmClientXBee.h
  30. +1102
    -606
      src/TinyGsmCommon.h
  31. +22
    -5
      tools/test_build/test_build.ino

+ 110
- 0
.clang-format View 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
- 0
.gitignore View File

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


+ 3
- 0
cpplint.cfg View File

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

+ 3
- 3
examples/AllFunctions/AllFunctions.ino View File

@ -42,7 +42,7 @@
//SoftwareSerial SerialAT(2, 3); // RX, TX
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
@ -68,8 +68,8 @@
#define GSM_PIN ""
// Set phone numbers, if you want to test SMS and Calls
//#define SMS_TARGET "+380xxxxxxxxx"
//#define CALL_TARGET "+380xxxxxxxxx"
// #define SMS_TARGET "+380xxxxxxxxx"
// #define CALL_TARGET "+380xxxxxxxxx"
// Your GPRS credentials, if any
const char apn[] = "YourAPN";


+ 1
- 1
examples/BlynkClient/BlynkClient.ino View File

@ -26,7 +26,7 @@
// Default heartbeat interval for GSM is 60
// If you want override this value, uncomment and set this option:
//#define BLYNK_HEARTBEAT 30
// #define BLYNK_HEARTBEAT 30
// Select your modem:
#define TINY_GSM_MODEM_SIM800


+ 6
- 6
examples/FileDownload/FileDownload.ino View File

@ -52,14 +52,14 @@
#define TINY_GSM_RX_BUFFER 1024
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
//#define LOGGING // <- Logging is for the HTTP library
// #define LOGGING // <- Logging is for the HTTP library
// Add a reception delay - may be needed for a fast processor at a slow baud rate
//#define TINY_GSM_YIELD() { delay(2); }
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
@ -217,7 +217,7 @@ void loop() {
client.print("Connection: close\r\n\r\n");
// Let's see what the entire elapsed time is, from after we send the request.
unsigned long timeElapsed = millis();
uint32_t timeElapsed = millis();
SerialMon.println(F("Waiting for response header"));
@ -246,7 +246,7 @@ void loop() {
// SerialMon.print(c, HEX);
// SerialMon.print(' ');
// if (isprint(c))
// SerialMon.print((char) c);
// SerialMon.print(reinterpret_cast<char> c);
// else
// SerialMon.print('*');
// SerialMon.print(' ');
@ -301,7 +301,7 @@ void loop() {
while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) {
while (client.available()) {
uint8_t c = client.read();
//SerialMon.print((char)c); // Uncomment this to show data
//SerialMon.print(reinterpret_cast<char>c); // Uncomment this to show data
crc.update(c);
readLength++;
if (readLength % (contentLength / 13) == 0) {


+ 3
- 3
examples/HttpClient/HttpClient.ino View File

@ -57,18 +57,18 @@
#define TINY_GSM_RX_BUFFER 650
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
//#define LOGGING // <- Logging is for the HTTP library
// #define LOGGING // <- Logging is for the HTTP library
// Range to attempt to autobaud
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay - may be needed for a fast processor at a slow baud rate
//#define TINY_GSM_YIELD() { delay(2); }
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true


+ 3
- 3
examples/HttpsClient/HttpsClient.ino View File

@ -49,18 +49,18 @@
#define TINY_GSM_RX_BUFFER 650
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
//#define LOGGING // <- Logging is for the HTTP library
// #define LOGGING // <- Logging is for the HTTP library
// Range to attempt to autobaud
#define GSM_AUTOBAUD_MIN 9600
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay - may be needed for a fast processor at a slow baud rate
//#define TINY_GSM_YIELD() { delay(2); }
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true


+ 4
- 4
examples/MqttClient/MqttClient.ino View File

@ -60,7 +60,7 @@
//SoftwareSerial SerialAT(2, 3); // RX, TX
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
@ -70,7 +70,7 @@
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay - may be needed for a fast processor at a slow baud rate
//#define TINY_GSM_YIELD() { delay(2); }
// #define TINY_GSM_YIELD() { delay(2); }
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
@ -125,7 +125,7 @@ PubSubClient mqtt(client);
#define LED_PIN 13
int ledStatus = LOW;
long lastReconnectAttempt = 0;
uint32_t lastReconnectAttempt = 0;
void mqttCallback(char* topic, byte* payload, unsigned int len) {
SerialMon.print("Message arrived [");
@ -252,7 +252,7 @@ void loop() {
if (!mqtt.connected()) {
SerialMon.println("=== MQTT NOT CONNECTED ===");
// Reconnect every 10 seconds
unsigned long t = millis();
uint32_t t = millis();
if (t - lastReconnectAttempt > 10000L) {
lastReconnectAttempt = t;
if (mqttConnect()) {


+ 4
- 4
examples/WebClient/WebClient.ino View File

@ -47,7 +47,7 @@
#define TINY_GSM_RX_BUFFER 650
// See all AT commands, if wanted
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Define the serial console for debug prints, if needed
#define TINY_GSM_DEBUG SerialMon
@ -57,10 +57,10 @@
#define GSM_AUTOBAUD_MAX 115200
// Add a reception delay - may be needed for a fast processor at a slow baud rate
//#define TINY_GSM_YIELD() { delay(2); }
// #define TINY_GSM_YIELD() { delay(2); }
// Uncomment this if you want to use SSL
//#define USE_SSL
// #define USE_SSL
// Define how you're planning to connect to the internet
#define TINY_GSM_USE_GPRS true
@ -210,7 +210,7 @@ void loop() {
client.print("Connection: close\r\n\r\n");
client.println();
unsigned long timeout = millis();
uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {


+ 4
- 4
examples/more/Hologram_Dash/Hologram_Dash.ino View File

@ -12,15 +12,15 @@
#define TINY_GSM_MODEM_UBLOX
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
// #define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Uncomment this if you want to use SSL
//#define USE_SSL
// #define USE_SSL
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon Serial
@ -108,7 +108,7 @@ void loop() {
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis();
uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
// Print available data
while (client.available()) {


+ 3
- 3
examples/more/Industruino/Industruino.ino View File

@ -18,16 +18,16 @@
#define TINY_GSM_MODEM_SIM800
// Increase RX buffer if needed
//#define TINY_GSM_RX_BUFFER 512
// #define TINY_GSM_RX_BUFFER 512
#include <TinyGsmClient.h>
#include <ArduinoHttpClient.h>
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
// Uncomment this if you want to use SSL
//#define USE_SSL
// #define USE_SSL
// Set serial for debug console (to the Serial Monitor, speed 115200)
#define SerialMon SerialUSB


+ 1
- 1
examples/more/SIM800_SslSetCert/SIM800_SslSetCert.ino View File

@ -28,7 +28,7 @@
#define SerialAT Serial1
// Uncomment this if you want to see all AT commands
//#define DUMP_AT_COMMANDS
// #define DUMP_AT_COMMANDS
#ifdef DUMP_AT_COMMANDS


+ 87
- 88
src/TinyGsmClient.h View File

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

+ 227
- 361
src/TinyGsmClientA6.h View File

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

+ 228
- 425
src/TinyGsmClientBG96.h View File

@ -6,31 +6,23 @@
* @date Apr 2018
*/
#ifndef TinyGsmClientBG96_h
#define TinyGsmClientBG96_h
//#pragma message("TinyGSM: TinyGsmClientBG96")
#ifndef SRC_TINYGSMCLIENTBG96_H_
#define SRC_TINYGSMCLIENTBG96_H_
// #pragma message("TinyGSM: TinyGsmClientBG96")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 12
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
@ -39,474 +31,303 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
class TinyGsmBG96
: public TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT>;
class TinyGsmBG96: public TinyGsmUTFSMS<TinyGsmBG96>
{
public:
class GsmClient : public Client
{
friend class TinyGsmBG96;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
/*
* Inner Client
*/
public:
class GsmClientBG96 : public GsmClient {
friend class TinyGsmBG96;
public:
GsmClient() {}
public:
GsmClientBG96() {}
GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) {
init(&modem, mux);
}
explicit GsmClientBG96(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;
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;
at->sockets[mux] = this;
return true;
}
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);
}
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;
}
void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+QICLOSE="), mux);
sock_connected = false;
at->waitResponse();
}
void stop() override {
stop(15000L);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
/*
* Extended API
*/
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
at->sendAT(GF("+QICLOSE="), mux);
sock_connected = false;
at->waitResponse();
}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
virtual void stop() { stop(15000L); }
/*
* Inner Secure Client
*/
TINY_GSM_CLIENT_WRITE()
/*
class GsmClientSecureBG96 : public GsmClientBG96
{
public:
GsmClientSecure() {}
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
: public GsmClient(modem, mux)
{}
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
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;
}
};
*/
/*
* Extended API
* Constructor
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
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:
explicit TinyGsmBG96(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
// sendAT(GF("&FZ")); // Factory + Reset
// waitResponse();
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
#else
sendAT(GF("+CMEE=0")); // turn off error codes
#endif
waitResponse();
DBG(GF("### Modem:"), getModemName());
// Enable automatic time zone update
sendAT(GF("+CTZU=1"));
if (waitResponse(10000L) != 1) { return false; }
int ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return
// true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
return "Quectel BG96";
}
TINY_GSM_MODEM_SET_BAUD_IPR()
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 thisHasSSL() {
return false; // TODO(?): Add SSL support
}
bool hasWifi() {
bool thisHasWifi() {
return false;
}
bool hasGPRS() {
bool thisHasGPRS() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=1,1"));
if (waitResponse(60000L, GF("POWERED DOWN")) != 1) {
return false;
}
if (waitResponse(60000L, GF("POWERED DOWN")) != 1) { return false; }
waitResponse(5000L, GF("RDY"));
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+QPOWD=1"));
waitResponse(300); // returns OK first
return waitResponse(300, GF("POWERED DOWN")) == 1;
}
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
// When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
// is pulled up, the module can directly enter into sleep mode.If entering
// 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,
// and then the module can enter into sleep mode.
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+QSCLK="), enable);
return waitResponse() == 1;
}
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
protected:
String getSimCCIDImpl() {
sendAT(GF("+QCCID"));
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), 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
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
//Configure the TCPIP Context
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse() != 1) {
return false;
}
// Configure the TCPIP Context
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
GF("\""));
if (waitResponse() != 1) { return false; }
//Activate GPRS/CSD Context
// Activate GPRS/CSD Context
sendAT(GF("+QIACT=1"));
if (waitResponse(150000L) != 1) {
return false;
}
if (waitResponse(150000L) != 1) { return false; }
//Attach to Packet Domain service - is this necessary?
// Attach to Packet Domain service - is this necessary?
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1) {
return false;
}
if (waitResponse(60000L) != 1) { return false; }
return true;
}
bool gprsDisconnect() {
bool gprsDisconnectImpl() {
sendAT(GF("+QIDEACT=1")); // Deactivate the bearer context
if (waitResponse(40000L) != 1)
return false;
if (waitResponse(40000L) != 1) { return false; }
return true;
}
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* IP Address functions
*/
String getLocalIP() {
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());
}
protected:
// Can follow all of the IP functions from the template
/*
* Phone Call functions
*/
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
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;
}
protected:
// Can follow all of the phone call functions from the template
/*
* Messaging functions
*/
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;
}
protected:
// Follows all messaging functions per template
/*
* Location functions
*/
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery & temperature functions
* GPS location functions
*/
public:
// No functions of this type supported
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
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;
}
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery & temperature functions
*/
protected:
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* 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;
// <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();
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;
// <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE",
// "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer)
sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0"));
rsp = waitResponse();
if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) {
return false;
}
if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; }
if (stream.readStringUntil(',').toInt() != mux) {
return false;
}
if (stream.readStringUntil(',').toInt() != mux) { return false; }
// Read status
rsp = stream.readStringUntil('\n').toInt();
@ -515,28 +336,20 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
return 0;
}
// TODO: Wait for ACK? AT+QISEND=id,0
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
// TODO(?): Wait for ACK? AT+QISEND=id,0
return len;
}
size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+QIRD="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+QIRD:")) != 1) {
return 0;
}
if (waitResponse(GF("+QIRD:")) != 1) { return 0; }
int len = stream.readStringUntil('\n').toInt();
for (int i=0; i<len; i++) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
}
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
waitResponse();
DBG("### READ:", len, "from", mux);
sockets[mux]->sock_available = modemGetAvailable(mux);
@ -547,33 +360,28 @@ protected:
sendAT(GF("+QIRD="), mux, GF(",0"));
size_t result = 0;
if (waitResponse(GF("+QIRD:")) == 1) {
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip have read
result = stream.readStringUntil('\n').toInt();
if (result) {
DBG("### DATA AVAILABLE:", result, "on", mux);
}
if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); }
waitResponse();
}
if (!result) {
sockets[mux]->sock_connected = modemGetConnected(mux);
}
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
return result;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+QISTATE=1,"), mux);
//+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
// +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1"
if (waitResponse(GF("+QISTATE:")) != 1)
return false;
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
waitResponse();
@ -581,19 +389,16 @@ protected:
return 2 == res;
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -601,15 +406,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -648,38 +453,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientBG96* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTBG96_H_

+ 241
- 248
src/TinyGsmClientESP8266.h View File

@ -6,24 +6,21 @@
* @date Nov 2016
*/
#ifndef TinyGsmClientESP8266_h
#define TinyGsmClientESP8266_h
//#pragma message("TinyGSM: TinyGsmClientESP8266")
#ifndef SRC_TINYGSMCLIENTESP8266_H_
#define SRC_TINYGSMCLIENTESP8266_H_
// #pragma message("TinyGSM: TinyGsmClientESP8266")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 512
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 5
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
static unsigned TINY_GSM_TCP_KEEP_ALIVE = 120;
// <stat> status of ESP8266 station interface
// 2 : ESP8266 station connected to an AP and has obtained IP
@ -38,214 +35,187 @@ enum RegStatus {
REG_UNKNOWN = 6,
};
class TinyGsmESP8266
{
public:
class GsmClient : public Client
{
friend class TinyGsmESP8266;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
init(&modem, mux);
}
: public TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
virtual ~GsmClient(){}
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_connected = false;
/*
* Inner Client
*/
public:
class GsmClientESP8266 : public GsmClient {
friend class TinyGsmESP8266;
at->sockets[mux] = this;
public:
GsmClientESP8266() {}
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;
}
explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) {
init(&modem, mux);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_connected = false;
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false;
at->waitResponse(maxWaitMs);
rx.clear();
}
at->sockets[mux] = this;
virtual void stop() { stop(5000L); }
return true;
}
TINY_GSM_CLIENT_WRITE()
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);
}
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD();
at->sendAT(GF("+CIPCLOSE="), mux);
sock_connected = false;
at->waitResponse(maxWaitMs);
rx.clear();
}
void stop() override {
stop(5000L);
}
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
/*
* Extended API
*/
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Extended API
* Inner Secure Client
*/
public:
class GsmClientSecureESP8266 : public GsmClientESP8266 {
public:
GsmClientSecureESP8266() {}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1)
: GsmClientESP8266(modem, mux) {}
private:
TinyGsmESP8266* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
};
class GsmClientSecure : public GsmClient
{
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmESP8266& 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:
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;
}
};
TinyGsmESP8266(Stream& stream)
: stream(stream)
{
/*
* Constructor
*/
public:
explicit TinyGsmESP8266(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
if (!testAT()) { return false; }
if (pin && strlen(pin) > 0) {
DBG("ESP8266 modules do not use an unlock pin!");
}
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
sendAT(GF("+CIPMUX=1")); // Enable Multiple Connections
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
sendAT(GF("+CWMODE_CUR=1")); // Put into "station" mode
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
DBG(GF("### Modem:"), getModemName());
return true;
}
String getModemName() {
String getModemNameImpl() {
return "ESP8266";
}
void setBaud(unsigned long baud) {
void setBaudImpl(uint32_t baud) {
sendAT(GF("+UART_CUR="), baud, "8,1,0,0");
}
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
bool factoryDefaultImpl() {
sendAT(GF("+RESTORE"));
return waitResponse() == 1;
}
String getModemInfo() {
String getModemInfoImpl() {
sendAT(GF("+GMR"));
String res;
if (waitResponse(1000L, res) != 1) {
return "";
}
if (waitResponse(1000L, res) != 1) { return ""; }
res.replace(GSM_NL "OK" GSM_NL, "");
res.replace(GSM_NL, " ");
res.trim();
return res;
}
bool hasSSL() {
bool thisHasSSL() {
return true;
}
bool hasWifi() {
bool thisHasWifi() {
return true;
}
bool hasGPRS() {
bool thisHasGPRS() {
return false;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+RST"));
if (waitResponse(10000L) != 1) {
return false;
}
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) {
return false;
}
if (waitResponse(10000L) != 1) { return false; }
if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; }
delay(500);
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+GSLP=0")); // Power down indefinitely - until manually reset!
return waitResponse() == 1;
}
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* SIM card functions
*/
protected:
// SIM card functions don't apply
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN;
@ -255,52 +225,44 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
return (RegStatus)status;
}
/*
* Generic network functions
*/
int16_t getSignalQuality() {
protected:
int16_t getSignalQualityImpl() {
sendAT(GF("+CWJAP_CUR?"));
int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:"));
if (res1 != 2) {
waitResponse();
return 0;
}
streamSkipUntil(','); // Skip SSID
streamSkipUntil(','); // Skip BSSID/MAC address
streamSkipUntil(','); // Skip Chanel number
streamSkipUntil(','); // Skip SSID
streamSkipUntil(','); // Skip BSSID/MAC address
streamSkipUntil(','); // Skip Chanel number
int res2 = stream.parseInt(); // Read RSSI
waitResponse(); // Returns an OK after the value
waitResponse(); // Returns an OK after the value
return res2;
}
bool isNetworkConnected() {
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
if (s == REG_OK_IP || s == REG_OK_TCP) {
// with these, we're definitely connected
return true;
}
else if (s == REG_OK_NO_TCP) {
} else if (s == REG_OK_NO_TCP) {
// with this, we may or may not be connected
if (getLocalIP() == "") {
return false;
}
else {
} else {
return true;
}
}
else {
} else {
return false;
}
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* WiFi functions
*/
bool networkConnect(const char* ssid, const char* pwd) {
protected:
bool networkConnectImpl(const char* ssid, const char* pwd) {
sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\""));
if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) {
return false;
@ -309,7 +271,7 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
return true;
}
bool networkDisconnect() {
bool networkDisconnectImpl() {
sendAT(GF("+CWQAP"));
bool retVal = waitResponse(10000L) == 1;
waitResponse(GF("WIFI DISCONNECT"));
@ -319,74 +281,107 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
/*
* IP Address functions
*/
String getLocalIP() {
sendAT(GF("+CIPSTA_CUR??"));
protected:
String getLocalIPImpl() {
sendAT(GF("+CIPSTA_CUR?"));
int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:"));
if (res1 != 2) {
return "";
}
if (res1 != 2) { return ""; }
String res2 = stream.readStringUntil('"');
waitResponse();
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;
/*
* Battery & temperature functions
* 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;
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Location functions
*/
protected:
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Client related functions
* GPS location functions
*/
public:
// No functions of this type supported
protected:
/*
* Time functions
*/
protected:
String
getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* 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;
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75)
{
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
bool ssl = false, int timeout_s = 75) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
if (ssl) {
sendAT(GF("+CIPSSLSIZE=4096"));
waitResponse();
}
sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"),
GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE);
// TODO: Check mux
int rsp = waitResponse(timeout_ms,
GFP(GSM_OK),
GFP(GSM_ERROR),
GF("\",\""), host, GF("\","), port, GF(","),
TINY_GSM_TCP_KEEP_ALIVE);
// TODO(?): Check mux
int rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR),
GF("ALREADY CONNECT"));
// if (rsp == 3) waitResponse(); // May return "ERROR" after the "ALREADY CONNECT"
// if (rsp == 3) waitResponse();
// May return "ERROR" after the "ALREADY CONNECT"
return (1 == rsp);
}
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) {
return 0;
}
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
return len;
}
size_t modemRead(size_t, uint8_t) {
return 0;
}
size_t modemGetAvailable(uint8_t) {
return 0;
}
bool modemGetConnected(uint8_t mux) {
sendAT(GF("+CIPSTATUS"));
if (waitResponse(3000, GF("STATUS:")) != 1) return false;
if (waitResponse(3000, GF("STATUS:")) != 1) { return false; }
int status =
waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5"));
if (status != 3) {
@ -399,14 +394,15 @@ protected:
}
bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0};
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR));
uint8_t has_status =
waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR));
if (has_status == 1) {
int returned_mux = stream.readStringUntil(',').toInt();
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
streamSkipUntil(','); // Skip remote IP
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
streamSkipUntil(','); // Skip remote IP
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
streamSkipUntil('\n'); // Skip client/server type
verified_connections[returned_mux] = 1;
}
@ -418,19 +414,16 @@ protected:
return verified_connections[mux];
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -438,15 +431,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -463,25 +456,27 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5;
goto finish;
} else if (data.endsWith(GF("+IPD,"))) {
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(':').toInt();
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(':').toInt();
int len_orig = len;
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available");
DBG("### Buffer overflow: ", len, "received vs",
sockets[mux]->rx.free(), "available");
} else {
DBG("### Got Data: ", len, "on", mux);
}
while (len--) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
}
if (len_orig > sockets[mux]->available()) { // TODO
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(SRGDamia1): deal with buffer overflow/missed characters
if (len_orig > sockets[mux]->available()) {
DBG("### Fewer characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
data = "";
} else if (data.endsWith(GF("CLOSED"))) {
int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8));
int muxStart =
TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8));
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]) {
sockets[mux]->sock_connected = false;
}
@ -490,38 +485,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTESP8266_H_

+ 201
- 314
src/TinyGsmClientM590.h View File

@ -6,31 +6,23 @@
* @date Nov 2016
*/
#ifndef TinyGsmClientM590_h
#define TinyGsmClientM590_h
//#pragma message("TinyGSM: TinyGsmClientM590")
#ifndef SRC_TINYGSMCLIENTM590_H_
#define SRC_TINYGSMCLIENTM590_H_
// #pragma message("TinyGSM: TinyGsmClientM590")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 256
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 2
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 3,
REG_DENIED = 2,
@ -39,110 +31,89 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
class TinyGsmM590
{
public:
class GsmClient : public Client
{
friend class TinyGsmM590;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
: public TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
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;
}
/*
* Inner Client
*/
public:
class GsmClientM590 : public GsmClient {
friend class TinyGsmM590;
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);
public:
GsmClientM590() {}
return sock_connected;
}
explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 1) {
init(&modem, mux);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
bool init(TinyGsmM590* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_connected = false;
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_YIELD();
at->sendAT(GF("+TCPCLOSE="), mux);
sock_connected = false;
at->waitResponse(maxWaitMs);
rx.clear();
}
at->sockets[mux] = this;
virtual void stop() { stop(1000L); }
return true;
}
TINY_GSM_CLIENT_WRITE()
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);
}
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
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);
}
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
/*
* Extended API
*/
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Extended API
* Constructor
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmM590* at;
uint8_t mux;
bool sock_connected;
RxFifo rx;
};
public:
TinyGsmM590(Stream& stream)
: stream(stream)
{
public:
explicit TinyGsmM590(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
// sendAT(GF("&FZ")); // Factory + Reset
// waitResponse();
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
@ -158,76 +129,63 @@ public:
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return
// true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
// Doesn't support CGMI
String getModemNameImpl() {
return "Neoway M590";
}
TINY_GSM_MODEM_SET_BAUD_IPR()
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
// Extra stuff here - pwr save, internal stack
bool factoryDefaultImpl() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
sendAT(GF("+ICF=3,1")); // 8 data 0 parity 1 stop
waitResponse();
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
sendAT(GF("+ENPWRSAVE=0")); // Disable PWR save
waitResponse();
sendAT(GF("+XISP=0")); // Use internal stack
waitResponse();
sendAT(GF("&W")); // Write configuration
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
bool thisHasSSL() {
return false;
}
bool hasWifi() {
bool thisHasWifi() {
return false;
}
bool hasGPRS() {
bool thisHasGPRS() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=15"));
if (waitResponse(10000L) != 1) {
return false;
}
//MODEM:STARTUP
if (waitResponse(10000L) != 1) { return false; }
// MODEM:STARTUP
waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL));
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+CPWROFF"));
return waitResponse(3000L) == 1;
}
bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnable(bool enable = true) {
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+ENPWRSAVE="), enable);
return waitResponse() == 1;
}
@ -235,54 +193,29 @@ TINY_GSM_MODEM_GET_INFO_ATI()
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
TINY_GSM_MODEM_GET_SIMCCID_CCID()
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
protected:
// Able to follow all SIM card functions as inherited from the template
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+XISP=0"));
@ -292,44 +225,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
waitResponse();
if (!user) user = "";
if (!pwd) pwd = "";
if (!pwd) pwd = "";
sendAT(GF("+XGAUTH=1,1,\""), user, GF("\",\""), pwd, GF("\""));
waitResponse();
sendAT(GF("+XIIC=1"));
waitResponse();
const unsigned long timeout_ms = 60000L;
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
const uint32_t timeout_ms = 60000L;
for (uint32_t start = millis(); millis() - start < timeout_ms;) {
if (isGprsConnected()) {
//goto set_dns; // TODO
// goto set_dns; // TODO
return true;
}
delay(500);
}
return false;
// set_dns: // TODO
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
// waitResponse();
//
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
// waitResponse();
// set_dns: // TODO
// sendAT(GF("+DNSSERVER=1,8.8.8.8"));
// waitResponse();
//
// sendAT(GF("+DNSSERVER=2,8.8.4.4"));
// waitResponse();
return true;
}
bool gprsDisconnect() {
// TODO: There is no command in AT command set
bool gprsDisconnectImpl() {
// TODO(?): There is no command in AT command set
// XIIC=0 does not work
return true;
}
bool isGprsConnected() {
bool isGprsConnectedImpl() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
return false;
}
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; }
int res = stream.readStringUntil(',').toInt();
waitResponse();
return res == 1;
@ -338,12 +269,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* IP Address functions
*/
String getLocalIP() {
protected:
String getLocalIPImpl() {
sendAT(GF("+XIIC?"));
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; }
stream.readStringUntil(',');
String res = stream.readStringUntil('\n');
waitResponse();
@ -351,103 +280,64 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
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
*/
String sendUSSD(const String& code) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("D"), code);
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len)
TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
bool sendSMS_UTF16Impl(const String& number, const void* text,
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Location functions
*/
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
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
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;
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) {
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
for (int i=0; i<3; i++) { // TODO: no need for loop?
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool,
int timeout_s = 75) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
for (int i = 0; i < 3; i++) { // TODO(?): no need for loop?
String ip = dnsIpQuery(host);
sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port);
int rsp = waitResponse(timeout_ms,
GF(",OK" GSM_NL),
GF(",FAIL" GSM_NL),
GF("+TCPSETUP:Error" GSM_NL));
int rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL), GF(",FAIL" GSM_NL),
GF("+TCPSETUP:Error" GSM_NL));
if (1 == rsp) {
return true;
} else if (3 == rsp) {
@ -461,50 +351,49 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
stream.write((char)0x0D);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.write(static_cast<char>(0x0D));
stream.flush();
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) {
return 0;
}
if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; }
stream.readStringUntil('\n');
return len;
}
size_t modemRead(size_t, uint8_t) {
return 0;
}
size_t modemGetAvailable(uint8_t) {
return 0;
}
bool modemGetConnected(uint8_t 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();
return 1 == res;
}
String dnsIpQuery(const char* host) {
sendAT(GF("+DNS=\""), host, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) {
return "";
}
if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse(GF("+DNS:OK" GSM_NL));
res.trim();
return res;
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -512,15 +401,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -537,19 +426,19 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
index = 5;
goto finish;
} else if (data.endsWith(GF("+TCPRECV:"))) {
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(',').toInt();
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil(',').toInt();
int len_orig = len;
if (len > sockets[mux]->rx.free()) {
DBG("### Buffer overflow: ", len, "->", sockets[mux]->rx.free());
} else {
DBG("### Got: ", len, "->", sockets[mux]->rx.free());
}
while (len--) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
}
if (len_orig > sockets[mux]->available()) { // TODO
DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig);
while (len--) { moveCharFromStreamToFifo(mux); }
// TODO(?): Handle lost characters
if (len_orig > sockets[mux]->available()) {
DBG("### Fewer characters received than expected: ",
sockets[mux]->available(), " vs ", len_orig);
}
data = "";
} else if (data.endsWith(GF("+TCPCLOSE:"))) {
@ -563,38 +452,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTM590_H_

+ 250
- 429
src/TinyGsmClientM95.h View File

@ -2,35 +2,28 @@
* @file TinyGsmClientM95.h
* @author Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd.
* @license LGPL-3.0
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com>
* @copyright Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd.
* <http://www.replicade.com>
* @date Nov 2016
*/
#ifndef TinyGsmClientM95_h
#define TinyGsmClientM95_h
//#pragma message("TinyGSM: TinyGsmClientM95")
#ifndef SRC_TINYGSMCLIENTM95_H_
#define SRC_TINYGSMCLIENTM95_H_
// #pragma message("TinyGSM: TinyGsmClientM95")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 6
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
@ -39,132 +32,120 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
class TinyGsmM95
: public TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT>;
class TinyGsmM95: public TinyGsmUTFSMS<TinyGsmM95>
{
public:
class GsmClient : public Client
{
friend class TinyGsmM95;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
/*
* Inner Client
*/
public:
class GsmClientM95 : public GsmClient {
friend class TinyGsmM95;
public:
GsmClient() {}
public:
GsmClientM95() {}
GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
init(&modem, mux);
}
explicit GsmClientM95(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;
bool init(TinyGsmM95* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_available = 0;
sock_connected = false;
at->sockets[mux] = this;
at->sockets[mux] = this;
return true;
}
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);
}
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;
}
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);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
/*
* Extended API
*/
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"));
}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
virtual void stop() { stop(75000L); }
/*
* Inner Secure Client
*/
TINY_GSM_CLIENT_WRITE()
/*
class GsmClientSecureM95 : public GsmClientM95
{
public:
GsmClientSecure() {}
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
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;
}
};
*/
/*
* Extended API
* Constructor
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmM95* at;
uint8_t mux;
uint16_t sock_available;
bool sock_connected;
RxFifo rx;
};
// class GsmClientSecure : public GsmClient
// {
// public:
// GsmClientSecure() {}
//
// GsmClientSecure(TinyGsmm95& 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:
TinyGsmM95(Stream& stream)
: stream(stream)
{
public:
explicit TinyGsmM95(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
if (!testAT()) { return false; }
// sendAT(GF("&FZ")); // Factory + Reset
// waitResponse();
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
@ -175,62 +156,43 @@ public:
DBG(GF("### Modem:"), getModemName());
// Enable network time synchronization
sendAT(GF("+QNITZ=1"));
if (waitResponse(10000L) != 1) { return false; }
int ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return
// true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
return "Quectel M95";
bool thisHasSSL() {
return false; // TODO(?): Add SSL support
}
TINY_GSM_MODEM_SET_BAUD_IPR()
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_LISTEN()
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
return false; // TODO: For now
}
bool hasWifi() {
bool thisHasWifi() {
return false;
}
bool hasGPRS() {
bool thisHasGPRS() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
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;
}
sendAT(GF("+CFUN=1"));
@ -240,77 +202,51 @@ TINY_GSM_MODEM_GET_INFO_ATI()
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+QPOWD=1"));
return waitResponse(300, GF("NORMAL POWER DOWN")) == 1;
}
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
// When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
// is pulled up, the module can directly enter into sleep mode.If entering
// 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,
// and then the module can enter into sleep mode.
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+QSCLK="), enable);
return waitResponse() == 1;
}
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
protected:
String getSimCCIDImpl() {
sendAT(GF("+QCCID"));
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
void setHostFormat( bool useDottedQuad ) {
if ( useDottedQuad ) {
public:
void setHostFormat(bool useDottedQuad) {
if (useDottedQuad) {
sendAT(GF("+QIDNSIP=0"));
} else {
sendAT(GF("+QIDNSIP=1"));
@ -318,63 +254,47 @@ TINY_GSM_MODEM_GET_CSQ()
waitResponse();
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
// select foreground context 0 = VIRTUAL_UART_1
sendAT(GF("+QIFGCNT=0"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
//Select GPRS (=1) as the Bearer
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse() != 1) {
return false;
}
// Select GPRS (=1) as the Bearer
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
GF("\""));
if (waitResponse() != 1) { return false; }
// Select TCP/IP transfer mode - NOT transparent mode
sendAT(GF("+QIMODE=0"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
// Enable multiple TCP/IP connections
sendAT(GF("+QIMUX=1"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
//Start TCPIP Task and Set APN, User Name and Password
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" );
if (waitResponse() != 1) {
return false;
}
// Start TCPIP Task and Set APN, User Name and Password
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"");
if (waitResponse() != 1) { return false; }
//Activate GPRS/CSD Context
// Activate GPRS/CSD Context
sendAT(GF("+QIACT"));
if (waitResponse(60000L) != 1) {
return false;
}
if (waitResponse(60000L) != 1) { return false; }
// Check that we have a local IP address
if (localIP() == IPAddress(0,0,0,0)) {
return false;
}
if (localIP() == IPAddress(0, 0, 0, 0)) { return false; }
// Set Method to Handle Received TCP/IP Data
// Mode = 1 - Output a notification when data is received
// +QIRDI: <id>,<sc>,<sid>
sendAT(GF("+QINDI=1"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
// // Request an IP header for received data
// // "IPD(data length):"
@ -390,7 +310,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// 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):
// sendAT(GF("+QISHOWPT=0"));
// if (waitResponse() != 1) {
@ -407,18 +328,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
return true;
}
bool gprsDisconnect() {
sendAT(GF("+QIDEACT"));
bool gprsDisconnectImpl() {
sendAT(GF("+QIDEACT")); // Deactivate the bearer context
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
}
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* IP Address functions
*/
String getLocalIP() {
protected:
String getLocalIPImpl() {
sendAT(GF("+QILOCIP"));
stream.readStringUntil('\n');
String res = stream.readStringUntil('\n');
@ -426,147 +345,59 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
/*
* Messaging functions
*/
protected:
// Can follow all template functions
String sendUSSD(const String& code) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
public:
/** Delete all SMS */
bool deleteAllSMS() {
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 false;
}
/*
* Phone Call functions
* Location functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
protected:
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Location functions
* GPS location functions
*/
public:
// No functions of this type supported
String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
/*
* Battery & temperature functions
*/
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
uint16_t getBattVoltage() {
sendAT(GF("+CBC"));
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip 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() {
protected:
float getTemperatureImpl() {
sendAT(GF("+QTEMP"));
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
// milliVolts = stream.readStringUntil(',').toInt();
streamSkipUntil(','); // Skip thermistor charge
streamSkipUntil(','); // Skip thermistor charge
float temp = stream.readStringUntil('\n').toFloat();
// Wait for final OK
waitResponse();
@ -576,33 +407,25 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* Client related functions
*/
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
if (ssl) {
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, GF("\","), port);
int rsp = waitResponse(timeout_ms,
GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL));
return (1 == rsp);
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
if (ssl) { 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,
GF("\","), port);
int rsp =
waitResponse(timeout_ms, 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) {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
return 0;
}
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
// bool allAcknowledged = false;
// // bool failed = false;
@ -621,11 +444,11 @@ protected:
// }
// waitResponse(5000L);
return len; // TODO
return len; // TODO(?): get len/ack properly
}
size_t modemRead(size_t size, uint8_t mux) {
// TODO: Does this work????
// TODO(?): Does this work????
// AT+QIRD=<id>,<sc>,<sid>,<len>
// id = GPRS context number = 0, set in GPRS connect
// sc = role in connection = 1, client of connection
@ -641,40 +464,43 @@ protected:
streamSkipUntil(','); // skip connection type (TCP/UDP)
// read the real length of the retrieved data
uint16_t len = stream.readStringUntil('\n').toInt();
// We have no way of knowing in advance how much data will be in the buffer
// so when data is received we always assume the buffer is completely full.
// Chances are, this is not true and there's really not that much there.
// In that case, make sure we make sure we re-set the amount of data available.
if (len < size) {
sockets[mux]->sock_available = len;
}
for (uint16_t i=0; i<len; i++) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
// We have no way of knowing in advance how much data will be in the
// buffer so when data is received we always assume the buffer is
// completely full. Chances are, this is not true and there's really not
// that much there. In that case, make sure we make sure we re-set the
// amount of data available.
if (len < size) { sockets[mux]->sock_available = len; }
for (uint16_t i = 0; i < len; i++) {
moveCharFromStreamToFifo(mux);
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
DBG("### READ:", len, "from", mux);
return len;
} else {
sockets[mux]->sock_available = 0;
return 0;
sockets[mux]->sock_available = 0;
return 0;
}
}
size_t modemGetAvailable(uint8_t) {
return 0;
}
bool modemGetConnected(uint8_t 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:")))
return false;
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
waitResponse();
@ -682,19 +508,16 @@ protected:
return 2 == res;
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -702,15 +525,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -738,9 +561,9 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
data = "";
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int nl = data.lastIndexOf(GSM_NL, data.length()-8);
int coma = data.indexOf(',', nl+2);
int mux = data.substring(nl+2, coma).toInt();
int nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int coma = data.indexOf(',', nl + 2);
int mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
@ -749,38 +572,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t
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);
}
public:
protected:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTM95_H_

+ 268
- 435
src/TinyGsmClientMC60.h View File

@ -9,32 +9,23 @@
*
*/
#ifndef TinyGsmClientMC60_h
#define TinyGsmClientMC60_h
//#pragma message("TinyGSM: TinyGsmClientMC60")
#ifndef SRC_TINYGSMCLIENTMC60_H_
#define SRC_TINYGSMCLIENTMC60_H_
// #pragma message("TinyGSM: TinyGsmClientMC60")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 6
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
SIM_ANTITHEFT_LOCKED = 3,
};
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
@ -43,178 +34,150 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
class TinyGsmMC60
: public TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT>;
class TinyGsmMC60: public TinyGsmUTFSMS<TinyGsmMC60>
{
public:
class GsmClient : public Client
{
friend class TinyGsmMC60;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
/*
* Inner Client
*/
public:
class GsmClientMC60 : public GsmClient {
friend class TinyGsmMC60;
public:
GsmClient() {}
public:
GsmClientMC60() {}
GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) {
init(&modem, mux);
}
explicit GsmClientMC60(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;
bool init(TinyGsmMC60* modem, uint8_t mux = 1) {
this->at = modem;
this->mux = mux;
sock_available = 0;
sock_connected = false;
at->sockets[mux] = this;
at->sockets[mux] = this;
return true;
}
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);
}
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;
}
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);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
/*
* Extended API
*/
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"));
}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
virtual void stop() { stop(75000L); }
/*
* Inner Secure Client
*/
TINY_GSM_CLIENT_WRITE()
/*
class GsmClientSecureMC60 : public GsmClientMC60
{
public:
GsmClientSecure() {}
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
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;
}
};
*/
/*
* Extended API
* Constructor
*/
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmMC60* at;
uint8_t mux;
uint16_t sock_available;
bool sock_connected;
RxFifo rx;
};
// class GsmClientSecure : public GsmClient
// {
// public:
// GsmClientSecure() {}
//
// GsmClientSecure(TinyGsmMC60& 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:
TinyGsmMC60(Stream& stream)
: stream(stream)
{
public:
explicit TinyGsmMC60(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
if (!testAT()) { return false; }
// sendAT(GF("&FZ")); // Factory + Reset
// waitResponse();
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { 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());
// Enable network time synchronization
sendAT(GF("+QNITZ=1"));
if (waitResponse(10000L) != 1) { return false; }
int ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return
// true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
#if defined(TINY_GSM_MODEM_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
*/
// bool hasSSL() {
* under development
*/
// bool thisHasSSL() {
// sendAT(GF("+QIPSSL=?"));
// if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
// return false;
@ -222,125 +185,106 @@ TINY_GSM_MODEM_GET_INFO_ATI()
// return waitResponse() == 1;
// }
bool hasSSL() {
return false; // TODO: For now
bool thisHasSSL() {
return false; // TODO(?): Add SSL support
}
bool hasWifi() {
bool thisHasWifi() {
return false;
}
bool hasGPRS() {
bool thisHasGPRS() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
if (waitResponse(10000L) != 1) { return false; }
sendAT(GF("+CFUN=1,1"));
if (waitResponse(10000L) != 1) {
return false;
}
if (waitResponse(10000L) != 1) { return false; }
delay(3000);
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+QPOWD=1"));
return waitResponse(GF("NORMAL POWER DOWN")) == 1;
}
bool radioOff() {
if (!testAT()) {
return false;
}
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
// When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN
// is pulled up, the module can directly enter into sleep mode.If entering
// 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,
// and then the module can enter into sleep mode.
bool sleepEnableImpl(bool enable = true) {
sendAT(GF("+QSCLK="), enable);
return waitResponse() == 1;
}
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
TINY_GSM_MODEM_GET_SIMCCID_CCID()
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
protected:
SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) {
for (uint32_t 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"), 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();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 3: return SIM_LOCKED;
case 5:
case 6: return SIM_ANTITHEFT_LOCKED;
case 1: return SIM_READY;
case 6: return SIM_ANTITHEFT_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
// select foreground context 0 = VIRTUAL_UART_1
sendAT(GF("+QIFGCNT=0"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
//Select GPRS (=1) as the Bearer
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\""));
if (waitResponse() != 1) {
return false;
}
// Select GPRS (=1) as the Bearer
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
GF("\""));
if (waitResponse() != 1) { return false; }
//Define PDP context - is this necessary?
// Define PDP context - is this necessary?
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
waitResponse();
@ -350,56 +294,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// Select TCP/IP transfer mode - NOT transparent mode
sendAT(GF("+QIMODE=0"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
// Enable multiple TCP/IP connections
sendAT(GF("+QIMUX=1"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
//Start TCPIP Task and Set APN, User Name and Password
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"" );
if (waitResponse() != 1) {
return false;
}
// Start TCPIP Task and Set APN, User Name and Password
sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\"");
if (waitResponse() != 1) { return false; }
//Activate GPRS/CSD Context
// Activate GPRS/CSD Context
sendAT(GF("+QIACT"));
if (waitResponse(60000L) != 1) {
return false;
}
if (waitResponse(60000L) != 1) { return false; }
// Check that we have a local IP address
if (localIP() == IPAddress(0,0,0,0)) {
return false;
}
if (localIP() == IPAddress(0, 0, 0, 0)) { return false; }
//Set Method to Handle Received TCP/IP Data
// Set Method to Handle Received TCP/IP Data
// Mode=2 - Output a notification statement:
// +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>
sendAT(GF("+QINDI=2"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
return true;
}
bool gprsDisconnect() {
sendAT(GF("+QIDEACT"));
bool gprsDisconnectImpl() {
sendAT(GF("+QIDEACT")); // Deactivate the bearer context
return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1;
}
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* IP Address functions
*/
String getLocalIP() {
protected:
String getLocalIPImpl() {
sendAT(GF("+QILOCIP"));
stream.readStringUntil('\n');
String res = stream.readStringUntil('\n');
@ -407,61 +337,23 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
protected:
// Can follow all of the phone call functions from the template
/*
* Messaging functions
*/
protected:
// Can follow all template functions
String sendUSSD(const String& code) {
sendAT(GF("+CMGF=1"));
waitResponse();
sendAT(GF("+CSCS=\"HEX\""));
waitResponse();
sendAT(GF("+CUSD=1,\""), code, GF("\""));
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
return "";
}
stream.readStringUntil('"');
String hex = stream.readStringUntil('"');
stream.readStringUntil(',');
int dcs = stream.readStringUntil('\n').toInt();
if (waitResponse() != 1) {
return "";
}
if (dcs == 15) {
return TinyGsmDecodeHex8bit(hex);
} else if (dcs == 72) {
return TinyGsmDecodeHex16bit(hex);
} else {
return hex;
}
}
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
public:
/** Delete all SMS */
bool deleteAllSMS() {
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 false;
@ -470,118 +362,60 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* Location functions
*/
String getGsmLocation() {
sendAT(GF("+CIPGSMLOC=1,1"));
if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) {
return "";
}
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
protected:
// Can use CIPGSMLOC as inherited from the template
/*
* Battery & temperature functions
* GPS location functions
*/
public:
// No functions of this type supported
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
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;
}
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Battery & temperature functions
*/
protected:
float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Client related functions
*/
protected:
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
if (ssl) {
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, GF("\","), port);
int rsp = waitResponse(timeout_ms,
GF("CONNECT OK" GSM_NL),
GF("CONNECT FAIL" GSM_NL),
GF("ALREADY CONNECT" GSM_NL));
bool ssl = false, int timeout_s = 75) {
if (ssl) { 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,
GF("\","), port);
int rsp =
waitResponse(timeout_ms, 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) {
sendAT(GF("+QISEND="), mux, ',', (uint16_t)len);
if (waitResponse(GF(">")) != 1) {
return 0;
}
stream.write((uint8_t*)buff, len);
if (waitResponse(GF(">")) != 1) { return 0; }
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) {
return 0;
}
if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; }
bool allAcknowledged = false;
// bool failed = false;
while ( !allAcknowledged ) {
sendAT( GF("+QISACK"));
while (!allAcknowledged) {
sendAT(GF("+QISACK"));
if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) {
return -1;
} else {
streamSkipUntil(','); /** Skip total */
streamSkipUntil(','); /** Skip acknowledged data size */
if ( stream.readStringUntil('\n').toInt() == 0 ) {
if (stream.readStringUntil('\n').toInt() == 0) {
allAcknowledged = true;
}
}
@ -591,16 +425,16 @@ protected:
// streamSkipUntil(','); // Skip mux
// return stream.readStringUntil('\n').toInt();
return len; // TODO
return len; // TODO(?): verify len/ack
}
size_t modemRead(size_t size, uint8_t mux) {
// TODO: Does this work????
// TODO(?): Does this work????
// AT+QIRD=<id>,<sc>,<sid>,<len>
// id = GPRS context number - 0, set in GPRS connect
// sc = roll in connection - 1, client of connection
// sid = index of connection - mux
// len = maximum length of data to send
// id = GPRS context number = 0, set in GPRS connect
// sc = role in connection = 1, client of connection
// sid = index of connection = mux
// len = maximum length of data to retrieve
sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size);
// If it replies only OK for the write command, it means there is no
// 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
// be different sizes.
// If so, make sure we make sure we re-set the amount of data available.
if (len < size) {
sockets[mux]->sock_available = len;
}
for (uint16_t i=0; i<len; i++) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
if (len < size) { sockets[mux]->sock_available = len; }
for (uint16_t i = 0; i < len; i++) {
moveCharFromStreamToFifo(mux);
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);
return len;
} else {
sockets[mux]->sock_available = 0;
return 0;
sockets[mux]->sock_available = 0;
return 0;
}
}
size_t modemGetAvailable(uint8_t) {
return 0;
}
bool modemGetConnected(uint8_t 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:")))
return false;
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip socket type
streamSkipUntil(','); // Skip remote ip
streamSkipUntil(','); // Skip remote port
streamSkipUntil(','); // Skip local port
int res = stream.readStringUntil(',').toInt(); // socket state
waitResponse();
@ -652,19 +488,16 @@ protected:
return 2 == res;
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, 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) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -673,15 +506,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r6s(r6); r6s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -700,7 +533,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
} else if (r6 && data.endsWith(r6)) {
index = 6;
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>
streamSkipUntil(','); // Skip the context
streamSkipUntil(','); // Skip the role
@ -711,14 +545,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
// read the length of the current packet
int len_packet = stream.readStringUntil('\n').toInt();
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 = "";
DBG("### Got Data:", len, "on", mux);
DBG("### Got Data:", len_packet * num_packets, "on", mux);
} else if (data.endsWith(GF("CLOSED" GSM_NL))) {
int nl = data.lastIndexOf(GSM_NL, data.length()-8);
int coma = data.indexOf(',', nl+2);
int mux = data.substring(nl+2, coma).toInt();
int nl = data.lastIndexOf(GSM_NL, data.length() - 8);
int coma = data.indexOf(',', nl + 2);
int mux = data.substring(nl + 2, coma).toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
sockets[mux]->sock_connected = false;
}
@ -727,38 +561,37 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
{
uint8_t
waitResponse(uint32_t timeout_ms, 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) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL)
{
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientMC60* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTMC60_H_

+ 259
- 412
src/TinyGsmClientSIM5360.h
File diff suppressed because it is too large
View File


+ 279
- 556
src/TinyGsmClientSIM7000.h
File diff suppressed because it is too large
View File


+ 268
- 421
src/TinyGsmClientSIM7600.h
File diff suppressed because it is too large
View File


+ 271
- 579
src/TinyGsmClientSIM800.h
File diff suppressed because it is too large
View File


+ 40
- 55
src/TinyGsmClientSIM808.h View File

@ -6,34 +6,26 @@
* @date Nov 2016
*/
#ifndef TinyGsmClientSIM808_h
#define TinyGsmClientSIM808_h
//#pragma message("TinyGSM: TinyGsmClientSIM808")
#ifndef SRC_TINYGSMCLIENTSIM808_H_
#define SRC_TINYGSMCLIENTSIM808_H_
// #pragma message("TinyGSM: TinyGsmClientSIM808")
#include <TinyGsmClientSIM800.h>
class TinyGsmSim808: public TinyGsmSim800
{
public:
TinyGsmSim808(Stream& stream)
: TinyGsmSim800(stream)
{}
class TinyGsmSim808 : public TinyGsmSim800 {
public:
explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {}
/*
* GPS location functions
*/
public:
// enable GPS
bool enableGPS() {
// uint16_t state;
sendAT(GF("+CGNSPWR=1"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
return true;
}
@ -42,9 +34,7 @@ public:
// uint16_t state;
sendAT(GF("+CGNSPWR=0"));
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
return true;
}
@ -53,9 +43,7 @@ public:
// works only with ans SIM808 V2
String getGPSraw() {
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@ -64,23 +52,22 @@ public:
// get GPS informations
// works only with ans SIM808 V2
bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) {
//String buffer = "";
bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0,
int* vsat = 0, int* usat = 0) {
// String buffer = "";
// char chr_buffer[12];
bool fix = false;
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return false;
}
stream.readStringUntil(','); // mode
if ( stream.readStringUntil(',').toInt() == 1 ) fix = true;
stream.readStringUntil(','); //utctime
*lat = stream.readStringUntil(',').toFloat(); //lat
*lon = stream.readStringUntil(',').toFloat(); //lon
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); //lon
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
stream.readStringUntil(','); // mode
if (stream.readStringUntil(',').toInt() == 1) fix = true;
stream.readStringUntil(','); // utctime
*lat = stream.readStringUntil(',').toFloat(); // lat
*lon = stream.readStringUntil(',').toFloat(); // lon
if (alt != NULL) *alt = stream.readStringUntil(',').toFloat(); // lon
if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); // speed
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
@ -88,8 +75,10 @@ public:
stream.readStringUntil(',');
stream.readStringUntil(',');
stream.readStringUntil(',');
if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites
if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites
if (vsat != NULL)
*vsat = stream.readStringUntil(',').toInt(); // viewed satelites
if (usat != NULL)
*usat = stream.readStringUntil(',').toInt(); // used satelites
stream.readStringUntil('\n');
waitResponse();
@ -99,34 +88,31 @@ public:
// get GPS time
// 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;
char chr_buffer[12];
sendAT(GF("+CGNSINF"));
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) {
return false;
}
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
for (int i = 0; i < 3; i++) {
String buffer = stream.readStringUntil(',');
buffer.toCharArray(chr_buffer, sizeof(chr_buffer));
switch (i) {
case 0:
//mode
// mode
break;
case 1:
//fixstatus
if ( buffer.toInt() == 1 ) {
fix = buffer.toInt();
}
// fixstatus
if (buffer.toInt() == 1) { fix = buffer.toInt(); }
break;
case 2:
*year = buffer.substring(0,4).toInt();
*month = buffer.substring(4,6).toInt();
*day = buffer.substring(6,8).toInt();
*hour = buffer.substring(8,10).toInt();
*minute = buffer.substring(10,12).toInt();
*second = buffer.substring(12,14).toInt();
*year = buffer.substring(0, 4).toInt();
*month = buffer.substring(4, 6).toInt();
*day = buffer.substring(6, 8).toInt();
*hour = buffer.substring(8, 10).toInt();
*minute = buffer.substring(10, 12).toInt();
*second = buffer.substring(12, 14).toInt();
break;
default:
@ -135,7 +121,7 @@ public:
break;
}
}
String res = stream.readStringUntil('\n');
stream.readStringUntil('\n');
waitResponse();
if (fix) {
@ -144,7 +130,6 @@ public:
return false;
}
}
};
#endif
#endif // SRC_TINYGSMCLIENTSIM808_H_

+ 267
- 422
src/TinyGsmClientSaraR4.h
File diff suppressed because it is too large
View File


+ 264
- 401
src/TinyGsmClientSequansMonarch.h View File

@ -6,30 +6,22 @@
* @date Jan 2019
*/
#ifndef TinyGsmClientSequansMonarch_h
#define TinyGsmClientSequansMonarch_h
#ifndef SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
#define SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 6
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
@ -48,156 +40,144 @@ enum SocketStatus {
SOCK_OPENING = 6,
};
class TinyGsmSequansMonarch
{
public:
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);
}
: public TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
TINY_GSM_MUX_COUNT>;
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;
/*
* Inner Client
*/
public:
class GsmClientSequansMonarch : public GsmClient {
friend class TinyGsmSequansMonarch;
// 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;
public:
GsmClientSequansMonarch() {}
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;
}
explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem,
uint8_t mux = 1) {
init(&modem, mux);
}
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
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;
virtual void stop(uint32_t maxWaitMs) {
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
at->sendAT(GF("+SQNSH="), mux);
sock_connected = false;
at->waitResponse();
}
// 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;
virtual void stop() { stop(15000L); }
return true;
}
TINY_GSM_CLIENT_WRITE()
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);
}
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
void stop(uint32_t maxWaitMs) {
dumpModemBuffer(maxWaitMs);
at->sendAT(GF("+SQNSH="), mux);
sock_connected = false;
at->waitResponse();
}
void stop() override {
stop(15000L);
}
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
/*
* Extended API
*/
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Extended API
* Inner Secure Client
*/
public:
class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch {
public:
GsmClientSecureSequansMonarch() {}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem,
uint8_t mux = 1)
: GsmClientSequansMonarch(modem, mux) {}
private:
TinyGsmSequansMonarch* at;
uint8_t mux;
uint16_t sock_available;
uint32_t prev_check;
bool sock_connected;
bool got_data;
RxFifo rx;
};
class GsmClientSecure : public GsmClient {
public:
GsmClientSecure() {}
GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
virtual ~GsmClientSecure() {}
protected:
protected:
bool strictSSL = false;
public:
virtual int connect(const char* host, uint16_t port, int timeout_s) {
stop();
TINY_GSM_YIELD();
rx.clear();
// configure security profile 1 with parameters:
if (strictSSL) {
// require minimum of TLS 1.2 (3)
// only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
// verify server certificate against imported CA certs 0 and enforce
// validity period (3)
at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
} else {
// use TLS 1.0 or higher (1)
// support wider variety of cipher suites
// do not verify server certificate (0)
at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\""));
}
if (at->waitResponse() != 1) {
DBG("failed to configure security profile");
return false;
}
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
public:
int connect(const char* host, uint16_t port, int timeout_s) {
stop();
TINY_GSM_YIELD();
rx.clear();
// configure security profile 1 with parameters:
if (strictSSL) {
// require minimum of TLS 1.2 (3)
// only support cipher suite 0x3D: TLS_RSA_WITH_AES_256_CBC_SHA256
// verify server certificate against imported CA certs 0 and enforce
// validity period (3)
at->sendAT(GF("+SQNSPCFG=1,3,\"0x3D\",3,0,,,\"\",\"\""));
} else {
// use TLS 1.0 or higher (1)
// support wider variety of cipher suites
// do not verify server certificate (0)
at->sendAT(GF("+SQNSPCFG=1,1,\"0x2F;0x35;0x3C;0x3D\",0,,,,\"\",\"\""));
}
if (at->waitResponse() != 1) {
DBG("failed to configure security profile");
return false;
}
void setStrictSSL(bool strict) {
strictSSL = strict;
}
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
return sock_connected;
}
};
void setStrictSSL(bool strict) {
strictSSL = strict;
}
};
public:
TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
/*
* Constructor
*/
public:
explicit TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
/*
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
protected:
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
@ -209,133 +189,87 @@ public:
DBG(GF("### Modem:"), getModemName());
// Make sure the module is enabled. Unlike others, the VZN20Q powers on
// with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full functionality
// The module cannot even detect the sim card if the cellular functionality is disabled so
// unless we explicitly enable the functionality the init will fail.
// with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full
// functionality The module cannot even detect the sim card if the cellular
// functionality is disabled so unless we explicitly enable the
// functionality the init will fail.
sendAT(GF("+CFUN=1"));
waitResponse();
// Enable automatic time zome update
sendAT(GF("+CTZU=1"));
if (waitResponse(10000L) != 1) { return false; }
int ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return
// true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
// 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() {
void maintainImpl() {
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) {
sock->got_data = false;
sock->got_data = false;
sock->sock_available = modemGetAvailable(mux);
// modemGetConnected() always checks the state of ALL socks
modemGetConnected();
}
}
while (stream.available()) {
waitResponse(15, NULL, NULL);
}
while (stream.available()) { waitResponse(15, NULL, NULL); }
}
bool factoryDefault() {
sendAT(GF("&FZE0&W")); // Factory + Reset + Echo Off + Write
waitResponse();
sendAT(GF("+IPR=0")); // Auto-baud
waitResponse();
sendAT(GF("+IFC=0,0")); // No Flow Control
waitResponse();
sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop
waitResponse();
sendAT(GF("+CSCLK=0")); // Disable Slow Clock
waitResponse();
sendAT(GF("&W")); // Write configuration
return waitResponse() == 1;
bool thisHasGPRS() {
return true;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool thisHasWifi() {
return false;
}
bool hasSSL() {
bool thisHasSSL() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=0"));
int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ;
if (res != 1 && res != 3) {
return false;
}
int res =
waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART"));
if (res != 1 && res != 3) { return false; }
sendAT(GF("+CFUN=1,1"));
res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR));
if (res != 1 && res != 3) {
return false;
}
if (res != 1 && res != 3) { return false; }
delay(1000);
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"));
return waitResponse();
}
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return 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) {
// 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 sleepEnableImpl(bool enable = true) {
sendAT(GF("+SQNIPSCFG="), enable);
return waitResponse() == 1;
}
@ -343,68 +277,36 @@ TINY_GSM_MODEM_GET_INFO_ATI()
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
String getSimCCID() {
protected:
String getSimCCIDImpl() {
sendAT(GF("+SQNCCID"));
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
return res;
}
TINY_GSM_MODEM_GET_IMEI_GSN()
SimStatus getSimStatus(unsigned long timeout_ms = 10000L) {
for (unsigned long start = millis(); millis() - start < timeout_ms; ) {
sendAT(GF("+CPIN?"));
if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) {
delay(1000);
continue;
}
int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"));
waitResponse();
switch (status) {
case 2:
case 3: return SIM_LOCKED;
case 1: return SIM_READY;
default: return SIM_ERROR;
}
}
return SIM_ERROR;
}
TINY_GSM_MODEM_GET_REGISTRATION_XREG(CEREG)
TINY_GSM_MODEM_GET_OPERATOR_COPS()
/*
* Generic network functions
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CEREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
if (s == REG_OK_HOME || s == REG_OK_ROAMING) {
// DBG(F("connected with status:"), s);
return true;
} else {
return false;
}
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) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
// Define the PDP context (This uses context #3!)
@ -423,123 +325,89 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// Attach to GPRS
sendAT(GF("+CGATT=1"));
if (waitResponse(60000L) != 1)
return false;
if (waitResponse(60000L) != 1) { return false; }
return true;
}
bool gprsDisconnect() {
bool gprsDisconnectImpl() {
sendAT(GF("+CGATT=0"));
if (waitResponse(60000L) != 1)
return false;
if (waitResponse(60000L) != 1) { return false; }
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
*/
String getLocalIP() {
protected:
String getLocalIPImpl() {
sendAT(GF("+CGPADDR=3"));
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) {
return "";
}
if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; }
String res = stream.readStringUntil('\"');
waitResponse();
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* 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;
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sendSMS(const String& number, const String& text) {
sendAT(GF("+CMGF=1"));
waitResponse();
// Set GSM 7 bit default alphabet (3GPP TS 23.038)
sendAT(GF("+CSCS=\"GSM\""));
waitResponse();
sendAT(GF("+CMGS=\""), number, GF("\""));
if (waitResponse(GF(">")) != 1) {
return false;
}
stream.print(text);
stream.write((char)0x1A);
stream.flush();
return waitResponse(60000L) == 1;
}
bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Messaging functions
*/
protected:
// Follows all messaging functions per template
/*
* 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
*/
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
bool getBattStats(uint8_t& chargeState, int8_t& percent,
uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE;
float getTemperature() {
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;
float getTemperatureImpl() {
sendAT(GF("+SMDTH"));
if (waitResponse(10000L, GF("+SMDTH: ")) != 1) {
return (float)-9999;
return static_cast<float>(-9999);
}
String res;
if (waitResponse(1000L, res) != 1) {
return (float)-9999;
}
if (res.indexOf("ERROR") >= 0) {
return (float)-9999;
}
if (waitResponse(1000L, res) != 1) { return static_cast<float>(-9999); }
if (res.indexOf("ERROR") >= 0) { return static_cast<float>(-9999); }
return res.toFloat();
}
protected:
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
bool ssl = false, int timeout_s = 75) {
int rsp;
unsigned long startMillis = millis();
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
int rsp;
uint32_t startMillis = millis();
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
if (ssl) {
// enable SSl and use security profile 1
@ -552,24 +420,28 @@ protected:
}
// Socket configuration
//AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
// AT+SQNSCFG:<connId1>, <cid1>, <pktSz1>, <maxTo1>, <connTo1>, <txTo1>
// <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)
// <maxTo1> = Max timeout in seconds = 90 (default)
// <connTo1> = Connection timeout in hundreds of milliseconds = 600 (default)
// <txTo1> = Data sending timeout in hundreds of milliseconds, used for online data mode only = 50 (default)
// <connTo1> = Connection timeout in hundreds of milliseconds
// = 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"));
waitResponse(5000L);
// Socket configuration extended
//AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>, <listenAutoRsp1>, <sendDataMode1>
// AT+SQNSCFGEXT:<connId1>, <srMode1>, <recvDataMode1>, <keepalive1>,
// <listenAutoRsp1>, <sendDataMode1>
// <connId1> = Connection ID = mux
// <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
// <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"));
waitResponse(5000L);
@ -578,20 +450,20 @@ protected:
// <connId> = Connection ID = mux
// <txProt> = Transmission protocol = 0 - TCP (1 for UDP)
// <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
// <closureType> = Socket closure behaviour for TCP, has no effect for UDP = 0 - local port closes when remote does (default)
// <IPaddr> = Any valid IP address in the format xxx.xxx.xxx.xxx or any
// 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.
// <connMode> = Connection mode = 1 - command mode connection
// <acceptAnyRemote> = Applies to UDP only
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""), ",0,0,1");
rsp = waitResponse((timeout_ms - (millis() - startMillis)),
GFP(GSM_OK),
GFP(GSM_ERROR),
GF("NO CARRIER" GSM_NL)
);
sendAT(GF("+SQNSD="), mux, ",0,", port, ',', GF("\""), host, GF("\""),
",0,0,1");
rsp = waitResponse((timeout_ms - (millis() - startMillis)), GFP(GSM_OK),
GFP(GSM_ERROR), GF("NO CARRIER" GSM_NL));
// creation of socket failed immediately.
if (rsp != 1) return false;
if (rsp != 1) { return false; }
// wait until we get a good status
bool connected = false;
@ -602,7 +474,6 @@ protected:
return connected;
}
int modemSend(const void* buff, size_t len, uint8_t mux) {
if (sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected == false) {
DBG("### Sock closed, cannot send data!");
@ -611,7 +482,7 @@ protected:
sendAT(GF("+SQNSSENDEXT="), mux, ',', (uint16_t)len);
waitResponse(10000L, GF(GSM_NL "> "));
stream.write((uint8_t*)buff, len);
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse() != 1) {
DBG("### no OK after send");
@ -630,8 +501,8 @@ protected:
// delay(50);
// }
// if (gotPrompt) {
// stream.write((uint8_t*)buff, len);
// stream.write((char)0x1A);
// stream.write(reinterpret_cast<const uint8_t*>(buff), len);
// stream.write(reinterpret_cast<char>0x1A);
// stream.flush();
// if (waitResponse() != 1) {
// DBG("### no OK after send");
@ -642,12 +513,9 @@ protected:
// return 0;
}
size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+SQNSRECV="), mux, ',', (uint16_t)size);
if (waitResponse(GF("+SQNSRECV: ")) != 1) {
return 0;
}
if (waitResponse(GF("+SQNSRECV: ")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int len = stream.readStringUntil('\n').toInt();
for (int i = 0; i < len; i++) {
@ -670,9 +538,9 @@ protected:
sendAT(GF("+SQNSI="), mux);
size_t result = 0;
if (waitResponse(GF("+SQNSI:")) == 1) {
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip total sent
streamSkipUntil(','); // Skip total received
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip total sent
streamSkipUntil(','); // Skip total received
result = stream.readStringUntil(',').toInt(); // keep data not yet read
waitResponse();
}
@ -685,9 +553,7 @@ protected:
// six possible sockets.
sendAT(GF("+SQNSS"));
for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) {
break;
};
if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; }
uint8_t status = 0;
// if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no
// DBG("### Warning: misaligned mux numbers!");
@ -704,26 +570,24 @@ protected:
// SOCK_LISTENING = 4,
// SOCK_INCOMING = 5,
// SOCK_OPENING = 6,
sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \
((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING));
sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected =
((status != SOCK_CLOSED) && (status != SOCK_INCOMING) &&
(status != SOCK_OPENING));
}
waitResponse(); // Should be an OK at the end
return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected;
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -731,15 +595,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -760,7 +624,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
int len = stream.readStringUntil('\n').toInt();
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT &&
sockets[mux % TINY_GSM_MUX_COUNT]) {
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
sockets[mux % TINY_GSM_MUX_COUNT]->got_data = true;
sockets[mux % TINY_GSM_MUX_COUNT]->sock_available = len;
}
data = "";
@ -776,12 +640,10 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
// data.replace(GSM_NL, "/");
@ -790,23 +652,24 @@ finish:
}
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) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL,
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_

+ 241
- 362
src/TinyGsmClientUBLOX.h View File

@ -6,32 +6,23 @@
* @date Nov 2016
*/
#ifndef TinyGsmClientUBLOX_h
#define TinyGsmClientUBLOX_h
//#pragma message("TinyGSM: TinyGsmClientUBLOX")
#ifndef SRC_TINYGSMCLIENTUBLOX_H_
#define SRC_TINYGSMCLIENTUBLOX_H_
// #pragma message("TinyGSM: TinyGsmClientUBLOX")
//#define TINY_GSM_DEBUG Serial
#if !defined(TINY_GSM_RX_BUFFER)
#define TINY_GSM_RX_BUFFER 64
#endif
// #define TINY_GSM_DEBUG Serial
#define TINY_GSM_MUX_COUNT 7
#include <TinyGsmCommon.h>
#include "TinyGsmCommon.h"
#define GSM_NL "\r\n"
static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL;
static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL;
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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:";
enum SimStatus {
SIM_ERROR = 0,
SIM_READY = 1,
SIM_LOCKED = 2,
};
enum RegStatus {
REG_NO_RESULT = -1,
REG_UNREGISTERED = 0,
REG_SEARCHING = 2,
REG_DENIED = 3,
@ -40,127 +31,115 @@ enum RegStatus {
REG_UNKNOWN = 4,
};
class TinyGsmUBLOX
{
: public TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> {
friend class TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE,
TINY_GSM_MUX_COUNT>;
public:
class GsmClient : public Client
{
friend class TinyGsmUBLOX;
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
public:
GsmClient() {}
/*
* Inner Client
*/
public:
class GsmClientUBLOX : public GsmClient {
friend class TinyGsmUBLOX;
GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) {
init(&modem, mux);
}
public:
GsmClientUBLOX() {}
virtual ~GsmClient(){}
explicit GsmClientUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0) {
init(&modem, mux);
}
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;
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;
at->sockets[mux] = this;
return true;
}
return true;
}
public:
virtual int connect(const char *host, uint16_t port, int timeout_s) {
stop();
TINY_GSM_YIELD();
rx.clear();
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, false, timeout_s);
if (mux != oldMux) {
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); }
}
at->sockets[mux] = this;
at->maintain();
TINY_GSM_CLIENT_WRITE()
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);
}
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
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);
}
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
/*
* Extended API
*/
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
};
/*
* Extended API
* Inner Secure Client
*/
public:
class GsmClientSecureUBLOX : public GsmClientUBLOX {
public:
GsmClientSecureUBLOX() {}
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
private:
TinyGsmUBLOX* 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(TinyGsmUBLOX& modem, uint8_t mux = 1)
: GsmClient(modem, mux)
{}
explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 1)
: GsmClientUBLOX(modem, mux) {}
virtual ~GsmClientSecure(){}
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, true, timeout_s);
if (mux != oldMux) {
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;
}
at->sockets[mux] = this;
at->maintain();
return sock_connected;
}
};
};
public:
TinyGsmUBLOX(Stream& stream)
: stream(stream)
{
/*
* Constructor
*/
public:
explicit TinyGsmUBLOX(Stream& stream) : stream(stream) {
memset(sockets, 0, sizeof(sockets));
}
@ -168,21 +147,13 @@ public:
* Basic functions
*/
bool begin(const char* pin = NULL) {
return init(pin);
}
bool init(const char* pin = NULL) {
bool initImpl(const char* pin = NULL) {
DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION);
if (!testAT()) {
return false;
}
if (!testAT()) { return false; }
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) {
return false;
}
sendAT(GF("E0")); // Echo Off
if (waitResponse() != 1) { return false; }
#ifdef TINY_GSM_DEBUG
sendAT(GF("+CMEE=2")); // turn on verbose error codes
@ -193,176 +164,127 @@ public:
getModemName();
// Enable automatic time zome update
sendAT(GF("+CTZU=1"));
if (waitResponse(10000L) != 1) { return false; }
int ret = getSimStatus();
// if the sim isn't ready and a pin has been provided, try to unlock the sim
if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) {
simUnlock(pin);
return (getSimStatus() == SIM_READY);
}
// if the sim is ready, or it's locked but no pin has been provided, return true
else {
} else {
// if the sim is ready, or it's locked but no pin has been provided,
// return true
return (ret == SIM_READY || ret == SIM_LOCKED);
}
}
String getModemName() {
String getModemNameImpl() {
sendAT(GF("+CGMI"));
String res1;
if (waitResponse(1000L, res1) != 1) {
return "u-blox Cellular Modem";
}
if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; }
res1.replace(GSM_NL "OK" GSM_NL, "");
res1.trim();
sendAT(GF("+GMM"));
String res2;
if (waitResponse(1000L, res2) != 1) {
return "u-blox Cellular Modem";
}
if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; }
res2.replace(GSM_NL "OK" GSM_NL, "");
res2.trim();
String name = res1 + String(' ') + res2;
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!");
}
else if (name.startsWith("u-blox SARA-N2")) {
} else if (name.startsWith("u-blox SARA-N2")) {
DBG("### SARA N2 NB-IoT modems not supported!");
}
return name;
}
TINY_GSM_MODEM_SET_BAUD_IPR()
TINY_GSM_MODEM_TEST_AT()
TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
bool factoryDefault() {
bool factoryDefaultImpl() {
sendAT(GF("+UFACTORY=0,1")); // No factory restore, erase NVM
waitResponse();
sendAT(GF("+CFUN=16")); // Reset
sendAT(GF("+CFUN=16")); // Reset
return waitResponse() == 1;
}
TINY_GSM_MODEM_GET_INFO_ATI()
bool hasSSL() {
bool thisHasSSL() {
return true;
}
bool hasWifi() {
bool thisHasWifi() {
return false;
}
bool hasGPRS() {
bool thisHasGPRS() {
return true;
}
/*
* Power functions
*/
bool restart() {
if (!testAT()) {
return false;
}
protected:
bool restartImpl() {
if (!testAT()) { return false; }
sendAT(GF("+CFUN=16"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000); // TODO: Verify delay timing here
if (waitResponse(10000L) != 1) { return false; }
delay(3000); // TODO(?): Verify delay timing here
return init();
}
bool poweroff() {
bool powerOffImpl() {
sendAT(GF("+CPWROFF"));
return waitResponse(40000L) == 1;
}
bool radioOff() {
sendAT(GF("+CFUN=0"));
if (waitResponse(10000L) != 1) {
return false;
}
delay(3000);
return true;
}
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* SIM card functions
*/
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
TINY_GSM_MODEM_GET_SIMCCID_CCID()
String getIMEI() {
protected:
String getIMEIImpl() {
sendAT(GF("+CGSN"));
if (waitResponse(GF(GSM_NL)) != 1) {
return "";
}
if (waitResponse(GF(GSM_NL)) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
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
*/
public:
RegStatus getRegistrationStatus() {
return (RegStatus)getRegistrationStatusXREG("CGREG");
}
TINY_GSM_MODEM_GET_CSQ()
bool isNetworkConnected() {
protected:
bool isNetworkConnectedImpl() {
RegStatus s = getRegistrationStatus();
if (s == REG_OK_HOME || s == REG_OK_ROAMING)
return true;
else if (s == REG_UNKNOWN) // for some reason, it can hang at unknown..
return isGprsConnected();
else return false;
else
return false;
}
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
/*
* GPRS functions
*/
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
protected:
bool gprsConnectImpl(const char* apn, const char* user = NULL,
const char* pwd = NULL) {
gprsDisconnect();
sendAT(GF("+CGATT=1")); // attach to GPRS
if (waitResponse(360000L) != 1) {
return false;
}
if (waitResponse(360000L) != 1) { return false; }
// 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
@ -388,15 +310,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
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();
// Packet switched data action
// AT+UPSDA=<profile_id>,<action>
// 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,
// using the current parameters
sendAT(GF("+UPSDA=0,3")); // Activate the PDP context associated with profile 0
// action = 3: activate; it activates a PDP context with the specified
// profile, using the current parameters
sendAT(GF(
"+UPSDA=0,3")); // Activate the PDP context associated with profile 0
if (waitResponse(360000L) != 1) { // Should return ok
return false;
}
@ -406,12 +329,13 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
// for the active PDP context associated with the specified PSD profile.
// AT+UPSND=<profile_id>,<param_tag>
// 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
sendAT(GF("+UPSND=0,8")); // Check if PSD profile 0 is now active
// param_tag = 8: PSD profile status: if the profile is active the return
// 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"));
waitResponse(); // Should return another OK
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
if (waitResponse(180000L, GF("+UUPSDA: 0")) != 1) { // 0=successful
return false;
@ -424,89 +348,50 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
return true;
}
bool gprsDisconnect() {
sendAT(GF("+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
if (waitResponse(360000L) != 1) {
return false;
}
bool gprsDisconnectImpl() {
sendAT(GF(
"+UPSDA=0,4")); // Deactivate the PDP context associated with profile 0
if (waitResponse(360000L) != 1) { return false; }
sendAT(GF("+CGATT=0")); // detach from GPRS
if (waitResponse(360000L) != 1) {
return false;
}
if (waitResponse(360000L) != 1) { return false; }
return true;
}
TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
/*
* IP Address functions
*/
String getLocalIP() {
protected:
String getLocalIPImpl() {
sendAT(GF("+UPSND=0,0"));
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) {
return "";
}
streamSkipUntil(','); // Skip PSD profile
streamSkipUntil('\"'); // Skip request type
if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; }
streamSkipUntil(','); // Skip PSD profile
streamSkipUntil('\"'); // Skip request type
String res = stream.readStringUntil('\"');
if (waitResponse() != 1) {
return "";
}
if (waitResponse() != 1) { return ""; }
return res;
}
IPAddress localIP() {
return TinyGsmIpFromString(getLocalIP());
}
/*
* Phone Call functions
*/
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
protected:
// Can follow all of the phone call functions from the template
/*
* Messaging functions
*/
String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
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;
protected:
// Can follow all template functions
/*
* Location functions
*/
String getGsmLocation() {
protected:
String getGsmLocationImpl() {
sendAT(GF("+ULOC=2,3,0,120,1"));
if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) {
return "";
}
if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; }
String res = stream.readStringUntil('\n');
waitResponse();
res.trim();
@ -514,48 +399,58 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
}
/*
* Battery & temperature functions
* GPS location functions
*/
public:
// No functions of this type supported
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
/*
* Time functions
*/
protected:
// Can follow the standard CCLK function in the template
/*
* Battery & temperature functions
*/
protected:
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
int8_t getBattPercent() {
int8_t getBattPercentImpl() {
sendAT(GF("+CIND?"));
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) {
return 0;
}
if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; }
int res = stream.readStringUntil(',').toInt();
int8_t percent = res*20; // return is 0-5
int res = stream.readStringUntil(',').toInt();
int8_t percent = res * 20; // return is 0-5
// Wait for final OK
waitResponse();
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;
percent = getBattPercent();
milliVolts = 0;
percent = getBattPercent();
milliVolts = 0;
return true;
}
// This would only available for a small number of modules in this group (TOBY-L)
float getTemperature() TINY_GSM_ATTR_NOT_IMPLEMENTED;
// This would only available for a small number of modules in this group
// (TOBY-L)
float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
/*
* Client related functions
*/
protected:
protected:
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
bool ssl = false, int timeout_s = 120)
{
uint32_t timeout_ms = ((uint32_t)timeout_s)*1000;
bool ssl = false, int timeout_s = 120) {
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
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;
}
*mux = stream.readStringUntil('\n').toInt();
@ -571,8 +466,8 @@ protected:
waitResponse();
// Enable KEEPALIVE, 30 sec
//sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
//waitResponse();
// sendAT(GF("+USOSO="), *mux, GF(",6,2,30000"));
// waitResponse();
// connect on the allocated socket
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
@ -582,17 +477,13 @@ protected:
int16_t modemSend(const void* buff, size_t len, uint8_t mux) {
sendAT(GF("+USOWR="), mux, ',', (uint16_t)len);
if (waitResponse(GF("@")) != 1) {
return 0;
}
if (waitResponse(GF("@")) != 1) { return 0; }
// 50ms delay, see AT manual section 25.10.4
delay(50);
stream.write((uint8_t*)buff, len);
stream.write(reinterpret_cast<const uint8_t*>(buff), len);
stream.flush();
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip mux
if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int sent = stream.readStringUntil('\n').toInt();
waitResponse(); // sends back OK after the confirmation of number sent
return sent;
@ -600,16 +491,12 @@ protected:
size_t modemRead(size_t size, uint8_t mux) {
sendAT(GF("+USORD="), mux, ',', (uint16_t)size);
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) {
return 0;
}
streamSkipUntil(','); // Skip mux
if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; }
streamSkipUntil(','); // Skip mux
int len = stream.readStringUntil(',').toInt();
streamSkipUntil('\"');
for (int i=0; i<len; i++) {
TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT
}
for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); }
streamSkipUntil('\"');
waitResponse();
DBG("### READ:", len, "from", mux);
@ -620,19 +507,17 @@ protected:
size_t modemGetAvailable(uint8_t mux) {
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USORD="), mux, ",0");
size_t result = 0;
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
size_t result = 0;
uint8_t res = waitResponse(GF(GSM_NL "+USORD:"));
// Will give error "operation not allowed" when attempting to read a socket
// that you have already told to close
if (res == 1) {
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip mux
result = stream.readStringUntil('\n').toInt();
// if (result) DBG("### DATA AVAILABLE:", result, "on", mux);
waitResponse();
}
if (!result) {
sockets[mux]->sock_connected = modemGetConnected(mux);
}
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
DBG("### AVAILABLE:", result, "on", mux);
return result;
}
@ -641,11 +526,10 @@ protected:
// NOTE: Querying a closed socket gives an error "operation not allowed"
sendAT(GF("+USOCTL="), mux, ",10");
uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:"));
if (res != 1)
return false;
if (res != 1) { return false; }
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
streamSkipUntil(','); // Skip mux
streamSkipUntil(','); // Skip type
int result = stream.readStringUntil('\n').toInt();
// 0: the socket is in INACTIVE status (it corresponds to CLOSED status
// defined in RFC793 "TCP Protocol Specification" [112])
@ -663,19 +547,16 @@ protected:
return (result != 0);
}
public:
/*
Utilities
* Utilities
*/
TINY_GSM_MODEM_STREAM_UTILITIES()
// TODO: Optimize this!
uint8_t waitResponse(uint32_t timeout_ms, String& data,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
public:
// TODO(vshymanskyy): Optimize this!
uint8_t
waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL,
GsmConstStr r5 = NULL) {
/*String r1s(r1); r1s.trim();
String r2s(r2); r2s.trim();
String r3s(r3); r3s.trim();
@ -683,15 +564,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
String r5s(r5); r5s.trim();
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
data.reserve(64);
int index = 0;
unsigned long startMillis = millis();
int index = 0;
uint32_t startMillis = millis();
do {
TINY_GSM_YIELD();
while (stream.available() > 0) {
TINY_GSM_YIELD();
int a = stream.read();
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += (char)a;
if (a <= 0) continue; // Skip 0x00 bytes, just in case
data += static_cast<char>(a);
if (r1 && data.endsWith(r1)) {
index = 1;
goto finish;
@ -714,7 +595,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
int mux = stream.readStringUntil(',').toInt();
int len = stream.readStringUntil('\n').toInt();
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;
}
data = "";
@ -729,38 +610,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
}
}
} while (millis() - startMillis < timeout_ms);
finish:
finish:
if (!index) {
data.trim();
if (data.length()) {
DBG("### Unhandled:", data);
}
if (data.length()) { DBG("### Unhandled:", data); }
data = "";
}
//data.replace(GSM_NL, "/");
//DBG('<', index, '>', data);
// data.replace(GSM_NL, "/");
// DBG('<', index, '>', data);
return index;
}
uint8_t waitResponse(uint32_t timeout_ms,
GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
GsmConstStr r2 = GFP(GSM_ERROR),
GsmConstStr r3 = GFP(GSM_CME_ERROR),
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
String data;
return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5);
}
uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR),
GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL)
{
uint8_t
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);
}
public:
Stream& stream;
protected:
GsmClient* sockets[TINY_GSM_MUX_COUNT];
protected:
Stream& stream;
GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT];
const char* gsmNL = GSM_NL;
};
#endif
#endif // SRC_TINYGSMCLIENTUBLOX_H_

+ 565
- 510
src/TinyGsmClientXBee.h
File diff suppressed because it is too large
View File


+ 1102
- 606
src/TinyGsmCommon.h
File diff suppressed because it is too large
View File


+ 22
- 5
tools/test_build/test_build.ino View File

@ -25,23 +25,35 @@ void setup() {
void loop() {
// Test the start/restart functions
modem.restart();
// Test the basic functions
modem.init();
modem.begin();
modem.setBaud(115200);
modem.testAT();
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
#if defined(TINY_GSM_MODEM_HAS_GPRS)
modem.getSimCCID();
modem.getIMEI();
modem.getSimStatus();
modem.getRegistrationStatus();
modem.getOperator();
#endif
// Test the Networking functions
modem.getRegistrationStatus();
modem.getSignalQuality();
modem.localIP();
@ -61,7 +73,7 @@ void loop() {
client.print(String("Host: ") + server + "\r\n");
client.print("Connection: close\r\n\r\n");
unsigned long timeout = millis();
uint32_t timeout = millis();
while (client.connected() && millis() - timeout < 10000L) {
while (client.available()) {
client.read();
@ -77,4 +89,9 @@ void loop() {
#if defined(TINY_GSM_MODEM_HAS_WIFI)
modem.networkDisconnect();
#endif
// Test battery and temperature functions
// modem.getBattVoltage();
// modem.getBattPercent();
// modem.getTemperature();
}

Loading…
Cancel
Save