CRTP!!!! Totally untested
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
This commit is contained in:
110
.clang-format
Normal file
110
.clang-format
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: false
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: true
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ""
|
||||
MacroBlockEnd: ""
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: None
|
||||
# ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 60
|
||||
PenaltyReturnTypeOnItsOwnLine: 5
|
||||
PointerAlignment: Left
|
||||
PointerBindsToType: true
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
TabWidth: 2
|
||||
UseTab: Never
|
||||
---
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -20,6 +20,7 @@
|
||||
.clang_complete
|
||||
.gcc-flags.json
|
||||
platformio.ini
|
||||
extra_envs.ini
|
||||
lib/readme.txt
|
||||
include/readme.txt
|
||||
.atomrc.cson
|
||||
|
3
cpplint.cfg
Normal file
3
cpplint.cfg
Normal file
@@ -0,0 +1,3 @@
|
||||
# Allow references to be used to change values
|
||||
filter=-runtime/references
|
||||
filter=-build/namespaces
|
@@ -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) {
|
||||
|
@@ -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()) {
|
||||
|
@@ -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()) {
|
||||
|
@@ -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()) {
|
||||
|
@@ -6,126 +6,125 @@
|
||||
* @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>
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure;
|
||||
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>
|
||||
#include "TinyGsmClientSIM808.h"
|
||||
typedef TinyGsmSim808 TinyGsm;
|
||||
typedef TinyGsmSim808::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure;
|
||||
typedef TinyGsmSim808::GsmClientSim800 TinyGsmClient;
|
||||
typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_SIM900)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientSIM800.h>
|
||||
#include "TinyGsmClientSIM800.h"
|
||||
typedef TinyGsmSim800 TinyGsm;
|
||||
typedef TinyGsmSim800::GsmClient TinyGsmClient;
|
||||
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>
|
||||
#include "TinyGsmClientSIM7000.h"
|
||||
typedef TinyGsmSim7000 TinyGsm;
|
||||
typedef TinyGsmSim7000::GsmClient TinyGsmClient;
|
||||
// typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO!
|
||||
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>
|
||||
#include "TinyGsmClientSIM5360.h"
|
||||
typedef TinyGsmSim5360 TinyGsm;
|
||||
typedef TinyGsmSim5360::GsmClient TinyGsmClient;
|
||||
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>
|
||||
#include "TinyGsmClientSIM7600.h"
|
||||
typedef TinyGsmSim7600 TinyGsm;
|
||||
typedef TinyGsmSim7600::GsmClient TinyGsmClient;
|
||||
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>
|
||||
#include "TinyGsmClientUBLOX.h"
|
||||
typedef TinyGsmUBLOX TinyGsm;
|
||||
typedef TinyGsmUBLOX::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure;
|
||||
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>
|
||||
#include "TinyGsmClientSaraR4.h"
|
||||
typedef TinyGsmSaraR4 TinyGsm;
|
||||
typedef TinyGsmSaraR4::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure;
|
||||
typedef TinyGsmSaraR4::GsmClientSaraR4 TinyGsmClient;
|
||||
typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_M95)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientM95.h>
|
||||
#include "TinyGsmClientM95.h"
|
||||
typedef TinyGsmM95 TinyGsm;
|
||||
typedef TinyGsmM95::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmM95::GsmClientM95 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_BG96)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientBG96.h>
|
||||
#include "TinyGsmClientBG96.h"
|
||||
typedef TinyGsmBG96 TinyGsm;
|
||||
typedef TinyGsmBG96::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientA6.h>
|
||||
#include "TinyGsmClientA6.h"
|
||||
typedef TinyGsmA6 TinyGsm;
|
||||
typedef TinyGsmA6::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmA6::GsmClientA6 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_M590)
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#include <TinyGsmClientM590.h>
|
||||
#include "TinyGsmClientM590.h"
|
||||
typedef TinyGsmM590 TinyGsm;
|
||||
typedef TinyGsmM590::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmM590::GsmClientM590 TinyGsmClient;
|
||||
|
||||
#elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E)
|
||||
#include <TinyGsmClientMC60.h>
|
||||
#include "TinyGsmClientMC60.h"
|
||||
#define TINY_GSM_MODEM_HAS_GPRS
|
||||
#define TINY_GSM_MODEM_HAS_GPS
|
||||
typedef TinyGsmMC60 TinyGsm;
|
||||
typedef TinyGsmMC60::GsmClient TinyGsmClient;
|
||||
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>
|
||||
#include "TinyGsmClientESP8266.h"
|
||||
typedef TinyGsmESP8266 TinyGsm;
|
||||
typedef TinyGsmESP8266::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure;
|
||||
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>
|
||||
#include "TinyGsmClientXBee.h"
|
||||
typedef TinyGsmXBee TinyGsm;
|
||||
typedef TinyGsmXBee::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure;
|
||||
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>
|
||||
#include "TinyGsmClientSequansMonarch.h"
|
||||
typedef TinyGsmSequansMonarch TinyGsm;
|
||||
typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient;
|
||||
typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure;
|
||||
|
||||
typedef TinyGsmSequansMonarch::GsmClientSequansMonarch TinyGsmClient;
|
||||
typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch TinyGsmClientSecure;
|
||||
|
||||
#else
|
||||
#error "Please define GSM modem model"
|
||||
|
@@ -6,31 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientA6_h
|
||||
#define TinyGsmClientA6_h
|
||||
#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_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_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,27 +31,25 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmA6
|
||||
{
|
||||
: public TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientA6 : public GsmClient {
|
||||
friend class TinyGsmA6;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientA6() {}
|
||||
|
||||
GsmClient(TinyGsmA6& modem) {
|
||||
init(&modem);
|
||||
explicit GsmClientA6(TinyGsmA6& modem) {
|
||||
init(&modem, -1);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmA6* modem) {
|
||||
bool init(TinyGsmA6* modem, uint8_t) {
|
||||
this->at = modem;
|
||||
this->mux = -1;
|
||||
sock_connected = false;
|
||||
@@ -68,7 +58,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -80,71 +70,62 @@ public:
|
||||
}
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(1000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(1000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmA6* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
// Doesn't support SSL
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmA6(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
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,151 +144,90 @@ 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
|
||||
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();
|
||||
@@ -314,117 +235,90 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
if (!user) user = "";
|
||||
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++) {
|
||||
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();
|
||||
return (res == 1);
|
||||
|
||||
sendAT(GF("+COPS?"));
|
||||
if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; }
|
||||
streamSkipUntil('"'); // Skip mode and format
|
||||
String res = stream.readStringUntil('"');
|
||||
waitResponse();
|
||||
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) {
|
||||
if (waitResponse(5000L) != 1) { return false; }
|
||||
|
||||
if (waitResponse(60000L, GF(GSM_NL "+CIEV: \"CALL\",1"),
|
||||
GF(GSM_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (waitResponse(60000L,
|
||||
GF(GSM_NL "+CIEV: \"CALL\",1"),
|
||||
GF(GSM_NL "+CIEV: \"CALL\",0"),
|
||||
GFP(GSM_ERROR)) != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int rsp = waitResponse(60000L,
|
||||
GF(GSM_NL "+CIEV: \"SOUNDER\",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();
|
||||
@@ -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,37 +376,34 @@ 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
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
// Note - the clock probably has to be set manaually first
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
protected:
|
||||
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
int8_t getBattPercent() {
|
||||
int8_t getBattPercentImpl() {
|
||||
sendAT(GF("+CBC?"));
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; }
|
||||
streamSkipUntil(','); // Skip battery charge status
|
||||
// Read battery charge level
|
||||
int res = stream.readStringUntil('\n').toInt();
|
||||
@@ -525,23 +412,10 @@ 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;
|
||||
@@ -550,32 +424,25 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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();
|
||||
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;
|
||||
}
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; }
|
||||
int newMux = stream.readStringUntil('\n').toInt();
|
||||
|
||||
int rsp = waitResponse((timeout_ms - (millis() - startMillis)),
|
||||
GF("CONNECT OK" GSM_NL),
|
||||
GF("CONNECT FAIL" GSM_NL),
|
||||
GF("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();
|
||||
@@ -622,14 +490,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -654,11 +522,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
} 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:"))) {
|
||||
@@ -674,9 +542,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -684,25 +550,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientA6* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTA6_H_
|
||||
|
@@ -6,31 +6,23 @@
|
||||
* @date Apr 2018
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientBG96_h
|
||||
#define TinyGsmClientBG96_h
|
||||
#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_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_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,26 +31,24 @@ 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>
|
||||
{
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientBG96 : public GsmClient {
|
||||
friend class TinyGsmBG96;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientBG96() {}
|
||||
|
||||
GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) {
|
||||
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;
|
||||
@@ -80,433 +70,264 @@ public:
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+QICLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(15000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
// 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;
|
||||
// }
|
||||
// };
|
||||
/*
|
||||
class GsmClientSecureBG96 : public GsmClientBG96
|
||||
{
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
|
||||
GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1)
|
||||
: public GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
TinyGsmBG96(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
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";
|
||||
bool thisHasSSL() {
|
||||
return false; // TODO(?): Add SSL support
|
||||
}
|
||||
|
||||
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 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;
|
||||
}
|
||||
sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
|
||||
GF("\""));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// 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?
|
||||
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
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
// 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() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
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!");
|
||||
}
|
||||
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();
|
||||
// <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();
|
||||
|
||||
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);
|
||||
@@ -550,14 +363,10 @@ protected:
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -565,8 +374,7 @@ protected:
|
||||
sendAT(GF("+QISTATE=1,"), mux);
|
||||
// +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
|
||||
@@ -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();
|
||||
@@ -602,14 +407,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -651,9 +456,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -661,25 +464,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientBG96* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTBG96_H_
|
||||
|
@@ -6,23 +6,20 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientESP8266_h
|
||||
#define TinyGsmClientESP8266_h
|
||||
#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_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 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
|
||||
@@ -38,26 +35,24 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 6,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmESP8266
|
||||
{
|
||||
: public TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientESP8266 : public GsmClient {
|
||||
friend class TinyGsmESP8266;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientESP8266() {}
|
||||
|
||||
GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
||||
explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmESP8266* modem, uint8_t mux = 1) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
@@ -69,61 +64,54 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(5000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(5000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmESP8266* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
|
||||
class GsmClientSecure : public GsmClient
|
||||
{
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
class GsmClientSecureESP8266 : public GsmClientESP8266 {
|
||||
public:
|
||||
GsmClientSecureESP8266() {}
|
||||
|
||||
GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
virtual ~GsmClientSecure() {}
|
||||
explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1)
|
||||
: GsmClientESP8266(modem, mux) {}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -132,120 +120,102 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmESP8266(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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,11 +225,8 @@ 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) {
|
||||
@@ -274,33 +241,28 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
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;
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
protected:
|
||||
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool sendSMSImpl(const String& number,
|
||||
const String& text) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool sendSMS_UTF16Impl(const char* const number, const void* text,
|
||||
size_t len) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Location functions
|
||||
*/
|
||||
protected:
|
||||
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* GPS location functions
|
||||
*/
|
||||
public:
|
||||
// No functions of this type supported
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
String
|
||||
getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
|
||||
// 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;
|
||||
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)
|
||||
{
|
||||
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) {
|
||||
if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; }
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t modemRead(size_t, uint8_t) {
|
||||
return 0;
|
||||
}
|
||||
return len;
|
||||
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,7 +394,8 @@ 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
|
||||
@@ -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();
|
||||
@@ -439,14 +432,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -467,19 +460,21 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
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();
|
||||
if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) {
|
||||
@@ -493,9 +488,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -503,25 +496,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTESP8266_H_
|
||||
|
@@ -6,31 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientM590_h
|
||||
#define TinyGsmClientM590_h
|
||||
#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_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_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,26 +31,24 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmM590
|
||||
{
|
||||
: public TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientM590 : public GsmClient {
|
||||
friend class TinyGsmM590;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientM590() {}
|
||||
|
||||
GsmClient(TinyGsmM590& modem, uint8_t mux = 1) {
|
||||
explicit GsmClientM590(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;
|
||||
@@ -70,79 +60,60 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, timeout_s);
|
||||
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_YIELD();
|
||||
at->sendAT(GF("+TCPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse(maxWaitMs);
|
||||
rx.clear();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(1000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_READ_NO_MODEM_FIFO()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(1000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmM590* at;
|
||||
uint8_t mux;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmM590(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
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,25 +129,20 @@ 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
|
||||
@@ -189,45 +155,37 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN()
|
||||
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;
|
||||
}
|
||||
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"));
|
||||
@@ -299,8 +232,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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
|
||||
return true;
|
||||
@@ -319,17 +252,15 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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,102 +280,63 @@ 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) {
|
||||
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?
|
||||
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),
|
||||
int rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL), GF(",FAIL" GSM_NL),
|
||||
GF("+TCPSETUP:Error" GSM_NL));
|
||||
if (1 == rsp) {
|
||||
return true;
|
||||
@@ -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();
|
||||
@@ -513,14 +402,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -545,11 +434,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
} 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:"))) {
|
||||
@@ -566,9 +455,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -576,25 +463,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientM590* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTM590_H_
|
||||
|
@@ -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
|
||||
#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_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_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,26 +32,24 @@ 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>
|
||||
{
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientM95 : public GsmClient {
|
||||
friend class TinyGsmM95;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientM95() {}
|
||||
|
||||
GsmClient(TinyGsmM95& modem, uint8_t mux = 1) {
|
||||
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;
|
||||
@@ -71,100 +62,90 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
|
||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
at->sendAT(GF("+QICLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
|
||||
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);
|
||||
}
|
||||
|
||||
virtual void stop() { stop(75000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
uint32_t startMillis = millis();
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+QICLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
|
||||
GF("CLOSE OK"), GF("ERROR"));
|
||||
}
|
||||
void stop() override {
|
||||
stop(75000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmM95* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
// 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;
|
||||
// }
|
||||
// };
|
||||
/*
|
||||
class GsmClientSecureM95 : public GsmClientM95
|
||||
{
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
|
||||
GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
TinyGsmM95(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
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,75 +202,49 @@ 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;
|
||||
// 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;
|
||||
}
|
||||
delay(3000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
||||
|
||||
String getSimCCID() {
|
||||
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);
|
||||
}
|
||||
|
||||
public:
|
||||
void setHostFormat(bool useDottedQuad) {
|
||||
if (useDottedQuad) {
|
||||
sendAT(GF("+QIDNSIP=0"));
|
||||
@@ -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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// 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,57 +345,19 @@ 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"));
|
||||
@@ -486,82 +367,32 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Phone Call functions
|
||||
*/
|
||||
|
||||
bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
/*
|
||||
* Location functions
|
||||
*/
|
||||
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
|
||||
*/
|
||||
|
||||
// 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
|
||||
// Read charge of thermistor
|
||||
@@ -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!");
|
||||
}
|
||||
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));
|
||||
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,17 +464,17 @@ 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;
|
||||
}
|
||||
// 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
|
||||
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);
|
||||
@@ -662,12 +485,15 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
if (waitResponse(GF("+QISTATE:")))
|
||||
return false;
|
||||
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
|
||||
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip socket type
|
||||
@@ -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();
|
||||
@@ -703,14 +526,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -752,9 +575,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -762,25 +583,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientM95* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTM95_H_
|
||||
|
@@ -9,32 +9,23 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientMC60_h
|
||||
#define TinyGsmClientMC60_h
|
||||
#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_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_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,26 +34,24 @@ 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>
|
||||
{
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientMC60 : public GsmClient {
|
||||
friend class TinyGsmMC60;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientMC60() {}
|
||||
|
||||
GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) {
|
||||
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;
|
||||
@@ -75,146 +64,120 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, false, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
|
||||
TINY_GSM_CLIENT_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
at->sendAT(GF("+QICLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR"));
|
||||
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);
|
||||
}
|
||||
|
||||
virtual void stop() { stop(75000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
uint32_t startMillis = millis();
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+QICLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"),
|
||||
GF("CLOSE OK"), GF("ERROR"));
|
||||
}
|
||||
void stop() override {
|
||||
stop(75000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmMC60* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
bool sock_connected;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
// 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;
|
||||
// }
|
||||
// };
|
||||
/*
|
||||
class GsmClientSecureMC60 : public GsmClientMC60
|
||||
{
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
|
||||
GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
TinyGsmMC60(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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() {
|
||||
// bool thisHasSSL() {
|
||||
// sendAT(GF("+QIPSSL=?"));
|
||||
// if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) {
|
||||
// return false;
|
||||
@@ -222,75 +185,61 @@ 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;
|
||||
// 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;
|
||||
}
|
||||
sendAT(GF("+CFUN=0"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
delay(3000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
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:
|
||||
@@ -304,41 +253,36 @@ TINY_GSM_MODEM_GET_IMEI_GSN()
|
||||
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;
|
||||
}
|
||||
sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd,
|
||||
GF("\""));
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Define PDP context - is this necessary?
|
||||
sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"');
|
||||
@@ -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;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// 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=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,57 +337,19 @@ 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"));
|
||||
@@ -470,107 +362,49 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
||||
/*
|
||||
* Location functions
|
||||
*/
|
||||
protected:
|
||||
// Can use CIPGSMLOC as inherited from the template
|
||||
|
||||
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;
|
||||
}
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// 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() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
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 = 75) {
|
||||
if (ssl) {
|
||||
DBG("SSL not yet supported on this module!");
|
||||
}
|
||||
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));
|
||||
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;
|
||||
@@ -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,15 +449,14 @@ 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;
|
||||
}
|
||||
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
|
||||
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 {
|
||||
@@ -632,12 +465,15 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
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"
|
||||
|
||||
if (waitResponse(GF("+QISTATE:")))
|
||||
return false;
|
||||
if (waitResponse(GF("+QISTATE:")) != 1) { return false; }
|
||||
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip socket type
|
||||
@@ -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();
|
||||
@@ -674,14 +507,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -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
|
||||
@@ -714,7 +548,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
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);
|
||||
@@ -730,9 +564,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -740,25 +572,26 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientMC60* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTMC60_H_
|
||||
|
@@ -6,31 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientSIM5360_h
|
||||
#define TinyGsmClientSIM5360_h
|
||||
#ifndef SRC_TINYGSMCLIENTSIM5360_H_
|
||||
#define SRC_TINYGSMCLIENTSIM5360_H_
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
// #define TINY_GSM_USE_HEX
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 64
|
||||
#endif
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 10
|
||||
|
||||
#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_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,31 +31,25 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
enum TinyGSMDateTimeFormat {
|
||||
DATE_FULL = 0,
|
||||
DATE_TIME = 1,
|
||||
DATE_DATE = 2
|
||||
};
|
||||
|
||||
class TinyGsmSim5360: public TinyGsmUTFSMS<TinyGsmSim5360>
|
||||
{
|
||||
class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmSim5360, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientSim5360 : public GsmClient {
|
||||
friend class TinyGsmSim5360;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientSim5360() {}
|
||||
|
||||
GsmClient(TinyGsmSim5360& modem, uint8_t mux = 0) {
|
||||
explicit GsmClientSim5360(TinyGsmSim5360& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmSim5360* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
@@ -78,101 +64,115 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(15000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmSim5360* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
uint32_t prev_check;
|
||||
bool sock_connected;
|
||||
bool got_data;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
|
||||
// TODO(?): Add SSL support
|
||||
/*
|
||||
class GsmClientSecureSim5360 : public GsmClientSim5360 {
|
||||
public:
|
||||
GsmClientSecureSim5360() {}
|
||||
|
||||
explicit GsmClientSecureSim5360(TinyGsmSim5360& modem, uint8_t mux = 1)
|
||||
: GsmClientSim5360(modem, mux) {}
|
||||
|
||||
public:
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
sock_connected = at->modemConnect(host, port, mux, true, timeout_s);
|
||||
return sock_connected;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
TinyGsmSim5360(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
explicit TinyGsmSim5360(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
|
||||
#else
|
||||
sendAT(GF("+CMEE=0")); // turn off error codes
|
||||
#endif
|
||||
waitResponse();
|
||||
|
||||
DBG(GF("### Modem:"), 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() {
|
||||
String name = "SIMCom SIM5360";
|
||||
|
||||
sendAT(GF("+CGMM"));
|
||||
String res2;
|
||||
if (waitResponse(1000L, res2) != 1) {
|
||||
return name;
|
||||
}
|
||||
if (waitResponse(1000L, res2) != 1) { return name; }
|
||||
res2.replace(GSM_NL "OK" GSM_NL, "");
|
||||
res2.replace("_", " ");
|
||||
res2.trim();
|
||||
@@ -182,61 +182,47 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
||||
|
||||
TINY_GSM_MODEM_TEST_AT()
|
||||
|
||||
TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
|
||||
|
||||
bool factoryDefault() { // these commands aren't supported
|
||||
bool factoryDefaultImpl() { // these commands aren't supported
|
||||
return false;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
|
||||
bool hasSSL() {
|
||||
return false; // TODO: Module supports SSL, but not yet implemented
|
||||
bool thisHasSSL() {
|
||||
return false; // TODO(>): Module supports SSL, but not yet implemented
|
||||
}
|
||||
|
||||
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("+REBOOT"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
delay(3000L); // TODO: Test this delay!
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
delay(3000L); // TODO(?): Test this delay!
|
||||
return init();
|
||||
}
|
||||
|
||||
bool poweroff() {
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+CPOF"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool radioOff() {
|
||||
bool radioOffImpl() {
|
||||
sendAT(GF("+CFUN=4"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
delay(3000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sleepEnable(bool enable = true) {
|
||||
bool sleepEnableImpl(bool enable = true) {
|
||||
sendAT(GF("+CSCLK="), enable);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
@@ -244,85 +230,54 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
||||
|
||||
protected:
|
||||
// Gets the CCID of a sim card via AT+CCID
|
||||
String getSimCCID() {
|
||||
String getSimCCIDImpl() {
|
||||
sendAT(GF("+CICCID"));
|
||||
if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+ICCID:")) != 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(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();
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
public:
|
||||
String getNetworkModes() {
|
||||
sendAT(GF("+CNMP=?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
|
||||
String setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) {
|
||||
return "OK";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
|
||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect(); // Make sure we're not connected first
|
||||
|
||||
// Define the PDP context
|
||||
@@ -367,21 +322,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
waitResponse();
|
||||
|
||||
// Configure socket parameters
|
||||
//AT+CIPCCFG= [<NmRetry>][,[<DelayTm>][,[<Ack>][,[<errMode>][,]<HeaderType>][,[[<AsyncMode>][,[<TimeoutVal>]]]]]]]]
|
||||
// NmRetry = number of retransmission to be made for an IP packet = 10 (default)
|
||||
// DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default)
|
||||
// AT+CIPCCFG= <NmRetry>, <DelayTm>, <Ack>, <errMode>, <HeaderType>,
|
||||
// <AsyncMode>, <TimeoutVal>
|
||||
// NmRetry = number of retransmission to be made for an IP packet
|
||||
// = 10 (default)
|
||||
// DelayTm = number of milliseconds to delay before outputting received data
|
||||
// = 0 (default)
|
||||
// Ack = sets whether reporting a string “Send ok” = 0 (don't report)
|
||||
// errMode = mode of reporting error result code = 0 (numberic values)
|
||||
// HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,<link num>,<data length>”)
|
||||
// AsyncMode = sets mode of executing commands = 0 (synchronous command executing)
|
||||
// HeaderType = which data header of receiving data in multi-client mode
|
||||
// = 1 (“+RECEIVE,<link num>,<data length>”)
|
||||
// AsyncMode = sets mode of executing commands
|
||||
// = 0 (synchronous command executing)
|
||||
// TimeoutVal = minimum retransmission timeout in milliseconds = 75000
|
||||
sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Configure timeouts for opening and closing sockets
|
||||
// AT+CIPTIMEOUT=[<netopen_timeout>][, [<cipopen_timeout>][, [<cipsend_timeout>]]]
|
||||
// AT+CIPTIMEOUT=<netopen_timeout>, <cipopen_timeout>, <cipsend_timeout>
|
||||
sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000);
|
||||
waitResponse();
|
||||
|
||||
@@ -393,45 +351,36 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
// We to ignore any immediate response and wait for the
|
||||
// URC to show it's really connected.
|
||||
sendAT(GF("+NETOPEN"));
|
||||
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnect() {
|
||||
bool gprsDisconnectImpl() {
|
||||
// Close any open sockets
|
||||
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
|
||||
GsmClient *sock = sockets[mux];
|
||||
if (sock) {
|
||||
sock->stop();
|
||||
}
|
||||
GsmClientSim5360* sock = sockets[mux];
|
||||
if (sock) { sock->stop(); }
|
||||
}
|
||||
|
||||
// Stop the socket service
|
||||
// Note: all sockets should be closed first - on 3G/4G models the sockets must be closed manually
|
||||
// Note: all sockets should be closed first - on 3G/4G models the sockets
|
||||
// must be closed manually
|
||||
sendAT(GF("+NETCLOSE"));
|
||||
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isGprsConnected() {
|
||||
bool isGprsConnectedImpl() {
|
||||
sendAT(GF("+NETOPEN?"));
|
||||
// May return +NETOPEN: 1, 0. We just confirm that the first number is 1
|
||||
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; }
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
|
||||
// sendAT(GF("+CGPADDR=1")); // Show PDP address
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -439,112 +388,59 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* IP Address functions
|
||||
*/
|
||||
|
||||
String getLocalIP() {
|
||||
protected:
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
|
||||
// sendAT(GF("+CGPADDR=1")); // Show PDP address
|
||||
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() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
protected:
|
||||
bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool
|
||||
dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
|
||||
String sendUSSD(const String& code) {
|
||||
// Select message format (1=text)
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
// Select TE character set
|
||||
sendAT(GF("+CSCS=\"HEX\""));
|
||||
waitResponse();
|
||||
sendAT(GF("+CUSD=1,\""), code, GF("\""));
|
||||
if (waitResponse() != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
stream.readStringUntil('"');
|
||||
String hex = stream.readStringUntil('"');
|
||||
stream.readStringUntil(',');
|
||||
int dcs = stream.readStringUntil('\n').toInt();
|
||||
|
||||
if (dcs == 15) {
|
||||
return TinyGsmDecodeHex8bit(hex);
|
||||
} else if (dcs == 72) {
|
||||
return TinyGsmDecodeHex16bit(hex);
|
||||
} else {
|
||||
return hex;
|
||||
}
|
||||
}
|
||||
|
||||
bool sendSMS(const String& number, const String& text) {
|
||||
// Get SMS service centre address
|
||||
sendAT(GF("+AT+CSCA?"));
|
||||
waitResponse();
|
||||
// Select message format (1=text)
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
|
||||
sendAT(GF("+CSCS=\"GSM\""));
|
||||
waitResponse();
|
||||
// Send the message!
|
||||
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_IMPLEMENTED;
|
||||
protected:
|
||||
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
||||
|
||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
||||
uint16_t getBattVoltage() {
|
||||
protected:
|
||||
uint16_t getBattVoltageImpl() {
|
||||
sendAT(GF("+CBC"));
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }
|
||||
streamSkipUntil(','); // Skip battery charge status
|
||||
streamSkipUntil(','); // Skip battery charge level
|
||||
// get voltage in VOLTS
|
||||
@@ -556,36 +452,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
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() {
|
||||
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(',').toInt();
|
||||
// get voltage in VOLTS
|
||||
@@ -597,17 +467,13 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
}
|
||||
|
||||
// get temperature in degree celsius
|
||||
float getTemperature() {
|
||||
float getTemperatureImpl() {
|
||||
// Enable Temparature Reading
|
||||
sendAT(GF("+CMTE=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse() != 1) { return 0; }
|
||||
// Get Temparature Value
|
||||
sendAT(GF("+CMTE?"));
|
||||
if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { return false; }
|
||||
float res = stream.readStringUntil('\n').toFloat();
|
||||
// Wait for final OK
|
||||
waitResponse();
|
||||
@@ -617,58 +483,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* Client related functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 15) {
|
||||
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||
// Make sure we'll be getting data manually on this connection
|
||||
sendAT(GF("+CIPRXGET=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ssl) {
|
||||
DBG("SSL not yet supported on this module!");
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Establish a connection in multi-socket mode
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port);
|
||||
sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","),
|
||||
port);
|
||||
// The reply is +CIPOPEN: ## of socket created
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
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(GF(GSM_NL "+CIPSEND:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; }
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip requested bytes to send
|
||||
// TODO: make sure requested and confirmed bytes match
|
||||
// TODO(?): make sure requested and confirmed bytes match
|
||||
return stream.readStringUntil('\n').toInt();
|
||||
}
|
||||
|
||||
size_t modemRead(size_t size, uint8_t mux) {
|
||||
#ifdef TINY_GSM_USE_HEX
|
||||
sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
|
||||
#else
|
||||
sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
|
||||
#endif
|
||||
streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX
|
||||
streamSkipUntil(','); // Skip mux/cid (connecion id)
|
||||
@@ -679,13 +529,21 @@ protected:
|
||||
for (int i = 0; i < len_requested; i++) {
|
||||
uint32_t startMillis = millis();
|
||||
#ifdef TINY_GSM_USE_HEX
|
||||
while (stream.available() < 2 && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); }
|
||||
char buf[4] = { 0, };
|
||||
while (stream.available() < 2 &&
|
||||
(millis() - startMillis < sockets[mux]->_timeout)) {
|
||||
TINY_GSM_YIELD();
|
||||
}
|
||||
char buf[4] = {
|
||||
0,
|
||||
};
|
||||
buf[0] = stream.read();
|
||||
buf[1] = stream.read();
|
||||
char c = strtol(buf, NULL, 16);
|
||||
#else
|
||||
while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); }
|
||||
while (!stream.available() &&
|
||||
(millis() - startMillis < sockets[mux]->_timeout)) {
|
||||
TINY_GSM_YIELD();
|
||||
}
|
||||
char c = stream.read();
|
||||
#endif
|
||||
sockets[mux]->rx.put(c);
|
||||
@@ -707,19 +565,15 @@ protected:
|
||||
waitResponse();
|
||||
}
|
||||
DBG("### Available:", result, "on", mux);
|
||||
if (!result) {
|
||||
sockets[mux]->sock_connected = modemGetConnected(mux);
|
||||
}
|
||||
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
|
||||
return result;
|
||||
}
|
||||
|
||||
bool modemGetConnected(uint8_t mux) {
|
||||
// Read the status of all sockets at once
|
||||
sendAT(GF("+CIPCLOSE?"));
|
||||
if (waitResponse(GF("+CIPCLOSE:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
if (waitResponse(GF("+CIPCLOSE:")) != 1) { return false; }
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state>
|
||||
sockets[muxNo]->sock_connected = stream.parseInt();
|
||||
}
|
||||
@@ -727,19 +581,16 @@ protected:
|
||||
return sockets[mux]->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();
|
||||
@@ -748,14 +599,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -804,9 +655,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
// Need to close all open sockets and release the network library.
|
||||
// User will then need to reconnect.
|
||||
DBG("### Network error!");
|
||||
if (!isGprsConnected()) {
|
||||
gprsDisconnect();
|
||||
}
|
||||
if (!isGprsConnected()) { gprsDisconnect(); }
|
||||
data = "";
|
||||
}
|
||||
}
|
||||
@@ -814,9 +663,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -824,25 +671,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientSim5360* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTSIM5360_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,31 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientSIM7600_h
|
||||
#define TinyGsmClientSIM7600_h
|
||||
#ifndef SRC_TINYGSMCLIENTSIM7600_H_
|
||||
#define SRC_TINYGSMCLIENTSIM7600_H_
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
// #define TINY_GSM_USE_HEX
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 64
|
||||
#endif
|
||||
|
||||
#define TINY_GSM_MUX_COUNT 10
|
||||
|
||||
#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_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,31 +31,25 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
enum TinyGSMDateTimeFormat {
|
||||
DATE_FULL = 0,
|
||||
DATE_TIME = 1,
|
||||
DATE_DATE = 2
|
||||
};
|
||||
|
||||
class TinyGsmSim7600: public TinyGsmUTFSMS<TinyGsmSim7600>
|
||||
{
|
||||
class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmSim7600, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientSim7600 : public GsmClient {
|
||||
friend class TinyGsmSim7600;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientSim7600() {}
|
||||
|
||||
GsmClient(TinyGsmSim7600& modem, uint8_t mux = 0) {
|
||||
explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmSim7600* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
@@ -78,101 +64,91 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+CIPCLOSE="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(15000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmSim7600* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
uint32_t prev_check;
|
||||
bool sock_connected;
|
||||
bool got_data;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmSim7600(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
explicit TinyGsmSim7600(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
|
||||
#else
|
||||
sendAT(GF("+CMEE=0")); // turn off error codes
|
||||
#endif
|
||||
waitResponse();
|
||||
|
||||
DBG(GF("### Modem:"), 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() {
|
||||
String name = "SIMCom SIM7600";
|
||||
|
||||
sendAT(GF("+CGMM"));
|
||||
String res2;
|
||||
if (waitResponse(1000L, res2) != 1) {
|
||||
return name;
|
||||
}
|
||||
if (waitResponse(1000L, res2) != 1) { return name; }
|
||||
res2.replace(GSM_NL "OK" GSM_NL, "");
|
||||
res2.replace("_", " ");
|
||||
res2.trim();
|
||||
@@ -182,61 +158,47 @@ public:
|
||||
return name;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_SET_BAUD_IPR()
|
||||
|
||||
TINY_GSM_MODEM_TEST_AT()
|
||||
|
||||
TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS()
|
||||
|
||||
bool factoryDefault() { // these commands aren't supported
|
||||
bool factoryDefaultImpl() { // these commands aren't supported
|
||||
return false;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
|
||||
bool hasSSL() {
|
||||
return false; // TODO: Module supports SSL, but not yet implemented
|
||||
bool thisHasSSL() {
|
||||
return false; // TODO(?): Module supports SSL, but not yet implemented
|
||||
}
|
||||
|
||||
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("+CRESET"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
delay(5000L); // TODO: Test this delay!
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
delay(5000L); // TODO(?): Test this delay!
|
||||
return init();
|
||||
}
|
||||
|
||||
bool poweroff() {
|
||||
bool powerOffImpl() {
|
||||
sendAT(GF("+CPOF"));
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
|
||||
bool radioOff() {
|
||||
bool radioOffImpl() {
|
||||
sendAT(GF("+CFUN=4"));
|
||||
if (waitResponse(10000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(10000L) != 1) { return false; }
|
||||
delay(3000);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool sleepEnable(bool enable = true) {
|
||||
bool sleepEnableImpl(bool enable = true) {
|
||||
sendAT(GF("+CSCLK="), enable);
|
||||
return waitResponse() == 1;
|
||||
}
|
||||
@@ -244,85 +206,54 @@ TINY_GSM_MODEM_GET_INFO_ATI()
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
||||
|
||||
protected:
|
||||
// Gets the CCID of a sim card via AT+CCID
|
||||
String getSimCCID() {
|
||||
String getSimCCIDImpl() {
|
||||
sendAT(GF("+CICCID"));
|
||||
if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+ICCID:")) != 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(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();
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
public:
|
||||
String getNetworkModes() {
|
||||
sendAT(GF("+CNMP=?"));
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
|
||||
String setNetworkMode(uint8_t mode) {
|
||||
sendAT(GF("+CNMP="), mode);
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) {
|
||||
return "OK";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* GPRS functions
|
||||
*/
|
||||
|
||||
bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) {
|
||||
protected:
|
||||
bool gprsConnectImpl(const char* apn, const char* user = NULL,
|
||||
const char* pwd = NULL) {
|
||||
gprsDisconnect(); // Make sure we're not connected first
|
||||
|
||||
// Define the PDP context
|
||||
@@ -350,21 +281,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
waitResponse();
|
||||
|
||||
// Configure socket parameters
|
||||
//AT+CIPCCFG= [<NmRetry>][,[<DelayTm>][,[<Ack>][,[<errMode>][,]<HeaderType>][,[[<AsyncMode>][,[<TimeoutVal>]]]]]]]]
|
||||
// NmRetry = number of retransmission to be made for an IP packet = 10 (default)
|
||||
// DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default)
|
||||
// AT+CIPCCFG= <NmRetry>, <DelayTm>, <Ack>, <errMode>, <HeaderType>,
|
||||
// <AsyncMode>, <TimeoutVal>
|
||||
// NmRetry = number of retransmission to be made for an IP packet
|
||||
// = 10 (default)
|
||||
// DelayTm = number of milliseconds to delay before outputting received data
|
||||
// = 0 (default)
|
||||
// Ack = sets whether reporting a string “Send ok” = 0 (don't report)
|
||||
// errMode = mode of reporting error result code = 0 (numberic values)
|
||||
// HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,<link num>,<data length>”)
|
||||
// AsyncMode = sets mode of executing commands = 0 (synchronous command executing)
|
||||
// HeaderType = which data header of receiving data in multi-client mode
|
||||
// = 1 (“+RECEIVE,<link num>,<data length>”)
|
||||
// AsyncMode = sets mode of executing commands
|
||||
// = 0 (synchronous command executing)
|
||||
// TimeoutVal = minimum retransmission timeout in milliseconds = 75000
|
||||
sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Configure timeouts for opening and closing sockets
|
||||
// AT+CIPTIMEOUT=[<netopen_timeout>][, [<cipopen_timeout>][, [<cipsend_timeout>]]]
|
||||
// AT+CIPTIMEOUT=<netopen_timeout> <cipopen_timeout>, <cipsend_timeout>
|
||||
sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000);
|
||||
waitResponse();
|
||||
|
||||
@@ -376,38 +310,30 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
// We to ignore any immediate response and wait for the
|
||||
// URC to show it's really connected.
|
||||
sendAT(GF("+NETOPEN"));
|
||||
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnect() {
|
||||
|
||||
bool gprsDisconnectImpl() {
|
||||
// Close all sockets and stop the socket service
|
||||
// Note: On the LTE models, this single command closes all sockets and the service
|
||||
// Note: On the LTE models, this single command closes all sockets and the
|
||||
// service
|
||||
sendAT(GF("+NETCLOSE"));
|
||||
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isGprsConnected() {
|
||||
bool isGprsConnectedImpl() {
|
||||
sendAT(GF("+NETOPEN?"));
|
||||
// May return +NETOPEN: 1, 0. We just confirm that the first number is 1
|
||||
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; }
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
|
||||
// sendAT(GF("+CGPADDR=1")); // Show PDP address
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -415,120 +341,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* IP Address functions
|
||||
*/
|
||||
|
||||
String getLocalIP() {
|
||||
protected:
|
||||
String getLocalIPImpl() {
|
||||
sendAT(GF("+IPADDR")); // Inquire Socket PDP address
|
||||
// sendAT(GF("+CGPADDR=1")); // Show PDP address
|
||||
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() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
protected:
|
||||
bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool
|
||||
dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* Messaging functions
|
||||
*/
|
||||
|
||||
String sendUSSD(const String& code) {
|
||||
// Select message format (1=text)
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
// Select TE character set
|
||||
sendAT(GF("+CSCS=\"HEX\""));
|
||||
waitResponse();
|
||||
sendAT(GF("+CUSD=1,\""), code, GF("\""));
|
||||
if (waitResponse() != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
stream.readStringUntil('"');
|
||||
String hex = stream.readStringUntil('"');
|
||||
stream.readStringUntil(',');
|
||||
int dcs = stream.readStringUntil('\n').toInt();
|
||||
|
||||
if (dcs == 15) {
|
||||
return TinyGsmDecodeHex8bit(hex);
|
||||
} else if (dcs == 72) {
|
||||
return TinyGsmDecodeHex16bit(hex);
|
||||
} else {
|
||||
return hex;
|
||||
}
|
||||
}
|
||||
|
||||
bool sendSMS(const String& number, const String& text) {
|
||||
// Get SMS service centre address
|
||||
sendAT(GF("+AT+CSCA?"));
|
||||
waitResponse();
|
||||
// Select message format (1=text)
|
||||
sendAT(GF("+CMGF=1"));
|
||||
waitResponse();
|
||||
//Set GSM 7 bit default alphabet (3GPP TS 23.038)
|
||||
sendAT(GF("+CSCS=\"GSM\""));
|
||||
waitResponse();
|
||||
// Send the message!
|
||||
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_IMPLEMENTED;
|
||||
protected:
|
||||
String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* GPS location functions
|
||||
*/
|
||||
public:
|
||||
// enable GPS
|
||||
bool enableGPS() {
|
||||
sendAT(GF("+CGPS=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
bool disableGPS() {
|
||||
sendAT(GF("+CGPS=0"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
// get the RAW GPS output
|
||||
String getGPSraw() {
|
||||
sendAT(GF("+CGNSSINFO=32"));
|
||||
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return ""; }
|
||||
String res = stream.readStringUntil('\n');
|
||||
waitResponse();
|
||||
res.trim();
|
||||
@@ -541,9 +408,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
bool fix = false;
|
||||
|
||||
sendAT(GF("+CGNSSINFO"));
|
||||
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; }
|
||||
|
||||
// stream.readStringUntil(','); // mode
|
||||
if (stream.readStringUntil(',').toInt() == 1) fix = true;
|
||||
@@ -569,20 +434,21 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
|
||||
return fix;
|
||||
}
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
// Use: float vBatt = modem.getBattVoltage() / 1000.0;
|
||||
uint16_t getBattVoltage() {
|
||||
uint16_t getBattVoltageImpl() {
|
||||
sendAT(GF("+CBC"));
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; }
|
||||
|
||||
// get voltage in VOLTS
|
||||
float voltage = stream.readStringUntil('\n').toFloat();
|
||||
@@ -593,11 +459,11 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
return res;
|
||||
}
|
||||
|
||||
int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
bool getBattStats(uint8_t& chargeState, int8_t& percent,
|
||||
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||
uint16_t& milliVolts) {
|
||||
chargeState = 0;
|
||||
percent = 0;
|
||||
@@ -606,11 +472,9 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
}
|
||||
|
||||
// get temperature in degree celsius
|
||||
uint16_t getTemperature() {
|
||||
uint16_t getTemperatureImpl() {
|
||||
sendAT(GF("+CPMUTEMP"));
|
||||
if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { return 0; }
|
||||
// return temperature in C
|
||||
uint16_t res = stream.readStringUntil('\n').toInt();
|
||||
// Wait for final OK
|
||||
@@ -621,58 +485,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
/*
|
||||
* Client related functions
|
||||
*/
|
||||
|
||||
protected:
|
||||
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t mux,
|
||||
bool ssl = false, int timeout_s = 15) {
|
||||
if (ssl) {
|
||||
DBG("SSL not yet supported on this module!");
|
||||
}
|
||||
if (ssl) { DBG("SSL not yet supported on this module!"); }
|
||||
// Make sure we'll be getting data manually on this connection
|
||||
sendAT(GF("+CIPRXGET=1"));
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
|
||||
// Establish a connection in multi-socket mode
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","),
|
||||
port);
|
||||
// The reply is +CIPOPEN: ## of socket created
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; }
|
||||
return true;
|
||||
}
|
||||
|
||||
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(GF(GSM_NL "+CIPSEND:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; }
|
||||
streamSkipUntil(','); // Skip mux
|
||||
streamSkipUntil(','); // Skip requested bytes to send
|
||||
// TODO: make sure requested and confirmed bytes match
|
||||
// TODO(?): make sure requested and confirmed bytes match
|
||||
return stream.readStringUntil('\n').toInt();
|
||||
}
|
||||
|
||||
size_t modemRead(size_t size, uint8_t mux) {
|
||||
#ifdef TINY_GSM_USE_HEX
|
||||
sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size);
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
|
||||
#else
|
||||
sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size);
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) {
|
||||
return 0;
|
||||
}
|
||||
if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; }
|
||||
#endif
|
||||
streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX
|
||||
streamSkipUntil(','); // Skip mux/cid (connecion id)
|
||||
@@ -683,13 +531,21 @@ protected:
|
||||
for (int i = 0; i < len_requested; i++) {
|
||||
uint32_t startMillis = millis();
|
||||
#ifdef TINY_GSM_USE_HEX
|
||||
while (stream.available() < 2 && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); }
|
||||
char buf[4] = { 0, };
|
||||
while (stream.available() < 2 &&
|
||||
(millis() - startMillis < sockets[mux]->_timeout)) {
|
||||
TINY_GSM_YIELD();
|
||||
}
|
||||
char buf[4] = {
|
||||
0,
|
||||
};
|
||||
buf[0] = stream.read();
|
||||
buf[1] = stream.read();
|
||||
char c = strtol(buf, NULL, 16);
|
||||
#else
|
||||
while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); }
|
||||
while (!stream.available() &&
|
||||
(millis() - startMillis < sockets[mux]->_timeout)) {
|
||||
TINY_GSM_YIELD();
|
||||
}
|
||||
char c = stream.read();
|
||||
#endif
|
||||
sockets[mux]->rx.put(c);
|
||||
@@ -711,9 +567,7 @@ protected:
|
||||
waitResponse();
|
||||
}
|
||||
DBG("### Available:", result, "on", mux);
|
||||
if (!result) {
|
||||
sockets[mux]->sock_connected = modemGetConnected(mux);
|
||||
}
|
||||
if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); }
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -723,7 +577,7 @@ protected:
|
||||
if (waitResponse(GF("+CIPCLOSE:")) != 1) {
|
||||
// return false; // TODO: Why does this not read correctly?
|
||||
}
|
||||
for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) {
|
||||
// +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state>
|
||||
sockets[muxNo]->sock_connected = stream.parseInt();
|
||||
}
|
||||
@@ -731,19 +585,16 @@ protected:
|
||||
return sockets[mux]->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();
|
||||
@@ -752,14 +603,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -808,9 +659,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
// Need to close all open sockets and release the network library.
|
||||
// User will then need to reconnect.
|
||||
DBG("### Network error!");
|
||||
if (!isGprsConnected()) {
|
||||
gprsDisconnect();
|
||||
}
|
||||
if (!isGprsConnected()) { gprsDisconnect(); }
|
||||
data = "";
|
||||
}
|
||||
}
|
||||
@@ -818,9 +667,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -828,25 +675,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientSim7600* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTSIM7600_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -6,34 +6,26 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientSIM808_h
|
||||
#define TinyGsmClientSIM808_h
|
||||
#ifndef SRC_TINYGSMCLIENTSIM808_H_
|
||||
#define SRC_TINYGSMCLIENTSIM808_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientSIM808")
|
||||
|
||||
#include <TinyGsmClientSIM800.h>
|
||||
|
||||
|
||||
class TinyGsmSim808: public TinyGsmSim800
|
||||
{
|
||||
|
||||
class TinyGsmSim808 : public TinyGsmSim800 {
|
||||
public:
|
||||
|
||||
TinyGsmSim808(Stream& stream)
|
||||
: TinyGsmSim800(stream)
|
||||
{}
|
||||
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,15 +52,14 @@ 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) {
|
||||
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;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; }
|
||||
|
||||
stream.readStringUntil(','); // mode
|
||||
if (stream.readStringUntil(',').toInt() == 1) fix = true;
|
||||
@@ -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,13 +88,12 @@ 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(',');
|
||||
@@ -116,9 +104,7 @@ public:
|
||||
break;
|
||||
case 1:
|
||||
// fixstatus
|
||||
if ( buffer.toInt() == 1 ) {
|
||||
fix = buffer.toInt();
|
||||
}
|
||||
if (buffer.toInt() == 1) { fix = buffer.toInt(); }
|
||||
break;
|
||||
case 2:
|
||||
*year = buffer.substring(0, 4).toInt();
|
||||
@@ -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_
|
||||
|
@@ -6,32 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientSaraR4_h
|
||||
#define TinyGsmClientSaraR4_h
|
||||
#ifndef SRC_TINYGSMCLIENTSARAR4_H_
|
||||
#define SRC_TINYGSMCLIENTSARAR4_H_
|
||||
// #pragma message("TinyGSM: TinyGsmClientSaraR4")
|
||||
|
||||
// #define TINY_GSM_DEBUG Serial
|
||||
|
||||
#if !defined(TINY_GSM_RX_BUFFER)
|
||||
#define TINY_GSM_RX_BUFFER 64
|
||||
#endif
|
||||
|
||||
#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_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,23 +31,24 @@ enum RegStatus {
|
||||
REG_UNKNOWN = 4,
|
||||
};
|
||||
|
||||
class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmSaraR4, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT>;
|
||||
|
||||
class TinyGsmSaraR4
|
||||
{
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientSaraR4 : public GsmClient {
|
||||
friend class TinyGsmSaraR4;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientSaraR4() {}
|
||||
|
||||
GsmClient(TinyGsmSaraR4& modem, uint8_t mux = 0) { init(&modem, mux); }
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
explicit GsmClientSaraR4(TinyGsmSaraR4& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
bool init(TinyGsmSaraR4* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
@@ -72,7 +64,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -88,33 +80,25 @@ public:
|
||||
|
||||
return sock_connected;
|
||||
}
|
||||
virtual int connect(IPAddress ip, uint16_t port, int timeout_s) {
|
||||
String host;
|
||||
host.reserve(16);
|
||||
host += ip[0];
|
||||
host += ".";
|
||||
host += ip[1];
|
||||
host += ".";
|
||||
host += ip[2];
|
||||
host += ".";
|
||||
host += ip[3];
|
||||
return connect(host.c_str(), port, timeout_s);
|
||||
int connect(IPAddress ip, uint16_t port, int timeout_s) {
|
||||
return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s);
|
||||
}
|
||||
virtual int connect(const char* host, uint16_t port) {
|
||||
int connect(const char* host, uint16_t port) override {
|
||||
return connect(host, port, 120);
|
||||
}
|
||||
virtual int connect(IPAddress ip, uint16_t port) {
|
||||
int connect(IPAddress ip, uint16_t port) override {
|
||||
return connect(ip, port, 120);
|
||||
}
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
// We want to use an async socket close because the syncrhonous close of an
|
||||
// open socket is INCREDIBLY SLOW and the modem can freeze up. But we only
|
||||
// attempt the async close if we already KNOW the socket is open because
|
||||
// calling the async close on a closed socket and then attempting opening a
|
||||
// new socket causes the board to lock up for 2-3 minutes and then finally
|
||||
// return with a "new" socket that is immediately closed.
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
uint32_t startMillis = millis();
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
// We want to use an async socket close because the syncrhonous close of
|
||||
// an open socket is INCREDIBLY SLOW and the modem can freeze up. But we
|
||||
// only attempt the async close if we already KNOW the socket is open
|
||||
// because calling the async close on a closed socket and then attempting
|
||||
// opening a new socket causes the board to lock up for 2-3 minutes and
|
||||
// then finally return with a "new" socket that is immediately closed.
|
||||
// Attempting to close a socket that is already closed with a synchronous
|
||||
// close quickly returns an error.
|
||||
if (at->supportsAsyncSockets && sock_connected) {
|
||||
@@ -137,47 +121,30 @@ public:
|
||||
sock_connected = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual void stop() { stop(135000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(135000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmSaraR4* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
uint32_t prev_check;
|
||||
bool sock_connected;
|
||||
bool got_data;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
|
||||
class GsmClientSecure : public GsmClient
|
||||
{
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
class GsmClientSecureR4 : public GsmClientSaraR4 {
|
||||
public:
|
||||
GsmClientSecureR4() {}
|
||||
|
||||
GsmClientSecure(TinyGsmSaraR4& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
virtual ~GsmClientSecure(){}
|
||||
explicit GsmClientSecureR4(TinyGsmSaraR4& modem, uint8_t mux = 1)
|
||||
: GsmClientSaraR4(modem, mux) {}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -193,32 +160,28 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmSaraR4(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
explicit TinyGsmSaraR4(Stream& stream)
|
||||
: stream(stream),
|
||||
has2GFallback(false),
|
||||
supportsAsyncSockets(false) {
|
||||
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
|
||||
@@ -241,33 +204,33 @@ public:
|
||||
supportsAsyncSockets = true;
|
||||
}
|
||||
|
||||
// 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
|
||||
} else {
|
||||
// if the sim is ready, or it's locked but no pin has been provided,
|
||||
// return true
|
||||
else {
|
||||
return (ret == SIM_READY || ret == SIM_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
String getModemName() {
|
||||
// only difference in implementation is the warning on the wrong type
|
||||
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();
|
||||
|
||||
@@ -281,108 +244,65 @@ public:
|
||||
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("&F")); // Resets the current profile, other NVM not affected
|
||||
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:
|
||||
// using +CFUN=15 instead of the more common CFUN=1,1
|
||||
bool restartImpl() {
|
||||
if (!testAT()) { return false; }
|
||||
sendAT(GF("+CFUN=15"));
|
||||
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_AVAILABLE;
|
||||
|
||||
/*
|
||||
* SIM card functions
|
||||
*/
|
||||
|
||||
TINY_GSM_MODEM_SIM_UNLOCK_CPIN()
|
||||
|
||||
TINY_GSM_MODEM_GET_SIMCCID_CCID()
|
||||
|
||||
String getIMEI() {
|
||||
protected:
|
||||
// This uses "CGSN" instead of "GSN"
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
public:
|
||||
RegStatus getRegistrationStatus() {
|
||||
// Check first for EPS registration
|
||||
sendAT(GF("+CEREG?"));
|
||||
if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) {
|
||||
return REG_UNKNOWN;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { return REG_UNKNOWN; }
|
||||
streamSkipUntil(','); /* Skip format (0) */
|
||||
int status = stream.readStringUntil('\n').toInt();
|
||||
waitResponse();
|
||||
@@ -394,64 +314,43 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID()
|
||||
} else {
|
||||
// Otherwise, check generic network status
|
||||
sendAT(GF("+CREG?"));
|
||||
if (waitResponse(GF(GSM_NL "+CREG:")) != 1) {
|
||||
return REG_UNKNOWN;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { return REG_UNKNOWN; }
|
||||
streamSkipUntil(','); /* Skip format (0) */
|
||||
int status = stream.readStringUntil('\n').toInt();
|
||||
status = stream.readStringUntil('\n').toInt();
|
||||
waitResponse();
|
||||
return (RegStatus)status;
|
||||
}
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_GET_OPERATOR_COPS()
|
||||
|
||||
/*
|
||||
* Generic network functions
|
||||
*/
|
||||
|
||||
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;
|
||||
return (s == REG_OK_HOME || s == REG_OK_ROAMING);
|
||||
}
|
||||
|
||||
TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
|
||||
public:
|
||||
bool setURAT(uint8_t urat) {
|
||||
// AT+URAT=<SelectedAcT>[,<PreferredAct>[,<2ndPreferredAct>]]
|
||||
|
||||
sendAT(GF("+COPS=2")); // Deregister from network
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+URAT="), urat); // Radio Access Technology (RAT) selection
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
sendAT(GF("+COPS=0")); // Auto-register to the network
|
||||
if (waitResponse() != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse() != 1) { return false; }
|
||||
return restart();
|
||||
}
|
||||
|
||||
/*
|
||||
* 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; }
|
||||
|
||||
// Using CGDCONT sets up an "external" PCP context, i.e. a data connection
|
||||
// using the external IP stack (e.g. Windows dial up) and PPP link over the
|
||||
@@ -468,21 +367,17 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
waitResponse();
|
||||
|
||||
sendAT(GF("+CGACT=1,1")); // activate PDP profile/context 1
|
||||
if (waitResponse(150000L) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(150000L) != 1) { return false; }
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool gprsDisconnect() {
|
||||
bool gprsDisconnectImpl() {
|
||||
// Mark all the sockets as closed
|
||||
// This ensures that asynchronously closed sockets are marked closed
|
||||
for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) {
|
||||
GsmClient* sock = sockets[mux];
|
||||
if (sock && sock->sock_connected) {
|
||||
sock->sock_connected = false;
|
||||
}
|
||||
GsmClientSaraR4* sock = sockets[mux];
|
||||
if (sock && sock->sock_connected) { sock->sock_connected = false; }
|
||||
}
|
||||
|
||||
// sendAT(GF("+CGACT=0,1")); // Deactivate PDP context 1
|
||||
@@ -492,98 +387,71 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
}
|
||||
|
||||
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() {
|
||||
sendAT(GF("+CGPADDR"));
|
||||
if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) {
|
||||
return "";
|
||||
}
|
||||
streamSkipUntil(','); // Skip context id
|
||||
String res = stream.readStringUntil('\r');
|
||||
if (waitResponse() != 1) {
|
||||
return "";
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
IPAddress localIP() {
|
||||
return TinyGsmIpFromString(getLocalIP());
|
||||
}
|
||||
protected:
|
||||
// Can follow the template in all function
|
||||
|
||||
/*
|
||||
* 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:
|
||||
// While the AT commands for call answer and hang-up are nominally supported,
|
||||
// no voice calls are supported rendering them meaningless
|
||||
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) 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:
|
||||
String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
bool sendSMS_UTF16Impl(const String& number, const void* text,
|
||||
size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
/*
|
||||
* 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();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPS location functions
|
||||
*/
|
||||
public:
|
||||
// No functions of this type supported
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
protected:
|
||||
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
uint16_t getBattVoltage() 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
|
||||
@@ -592,50 +460,43 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
||||
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) {
|
||||
percent = getBattPercent();
|
||||
bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent,
|
||||
uint16_t& milliVolts) {
|
||||
chargeState = 0;
|
||||
percent = getBattPercent();
|
||||
milliVolts = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
float getTemperature() {
|
||||
float getTemperatureImpl() {
|
||||
// First make sure the temperature is set to be in celsius
|
||||
sendAT(GF("+UTEMP=0")); // Would use 1 for Fahrenheit
|
||||
if (waitResponse() != 1) {
|
||||
return (float)-9999;
|
||||
}
|
||||
if (waitResponse() != 1) { return static_cast<float>(-9999); }
|
||||
sendAT(GF("+UTEMP?"));
|
||||
if (waitResponse(GF(GSM_NL "+UTEMP:")) != 1) {
|
||||
return (float)-9999;
|
||||
return static_cast<float>(-9999);
|
||||
}
|
||||
int16_t res = stream.readStringUntil('\n').toInt();
|
||||
float temp = -9999;
|
||||
if (res != -1) {
|
||||
temp = ((float)res)/10;
|
||||
}
|
||||
if (res != -1) { temp = (static_cast<float>(res)) / 10; }
|
||||
return temp;
|
||||
}
|
||||
|
||||
/*
|
||||
* Client related functions
|
||||
*/
|
||||
|
||||
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;
|
||||
unsigned long startMillis = millis();
|
||||
uint32_t startMillis = millis();
|
||||
|
||||
// create a socket
|
||||
sendAT(GF("+USOCR=6"));
|
||||
// reply is +USOCR: ## of socket created
|
||||
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) {
|
||||
return false;
|
||||
}
|
||||
if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { return false; }
|
||||
*mux = stream.readStringUntil('\n').toInt();
|
||||
waitResponse();
|
||||
|
||||
@@ -668,35 +529,33 @@ protected:
|
||||
DBG("### Opening socket asynchronously! Socket cannot be used until "
|
||||
"the URC '+UUSOCO' appears.");
|
||||
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1");
|
||||
if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO:")) == 1) {
|
||||
if (waitResponse(timeout_ms - (millis() - startMillis),
|
||||
GF(GSM_NL "+UUSOCO:")) == 1) {
|
||||
stream.readStringUntil(',').toInt(); // skip repeated mux
|
||||
int connection_status = stream.readStringUntil('\n').toInt();
|
||||
DBG("### Waited", millis() - startMillis, "ms for socket to open");
|
||||
return (0 == connection_status);
|
||||
} else {
|
||||
DBG("### Waited", millis() - startMillis, "but never got socket open notice");
|
||||
DBG("### Waited", millis() - startMillis,
|
||||
"but never got socket open notice");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// use synchronous open
|
||||
sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port);
|
||||
int rsp = waitResponse(timeout_ms);
|
||||
int rsp = waitResponse(timeout_ms - (millis() - startMillis));
|
||||
return (1 == rsp);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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
|
||||
@@ -705,16 +564,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;
|
||||
}
|
||||
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);
|
||||
@@ -735,9 +590,7 @@ protected:
|
||||
// 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;
|
||||
}
|
||||
@@ -746,7 +599,7 @@ 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
|
||||
@@ -767,20 +620,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),
|
||||
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 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();
|
||||
@@ -789,14 +638,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -846,9 +695,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -856,8 +703,7 @@ finish:
|
||||
return index;
|
||||
}
|
||||
|
||||
uint8_t waitResponse(uint32_t timeout_ms,
|
||||
GsmConstStr r1 = GFP(GSM_OK),
|
||||
uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK),
|
||||
GsmConstStr r2 = GFP(GSM_ERROR),
|
||||
GsmConstStr r3 = GFP(GSM_CME_ERROR),
|
||||
GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) {
|
||||
@@ -865,20 +711,19 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientSaraR4* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
bool has2GFallback;
|
||||
bool supportsAsyncSockets;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTSARAR4_H_
|
||||
|
@@ -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_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_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,26 +40,27 @@ enum SocketStatus {
|
||||
SOCK_OPENING = 6,
|
||||
};
|
||||
|
||||
|
||||
class TinyGsmSequansMonarch
|
||||
{
|
||||
: public TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT> {
|
||||
friend class TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE,
|
||||
TINY_GSM_MUX_COUNT>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientSequansMonarch : public GsmClient {
|
||||
friend class TinyGsmSequansMonarch;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientSequansMonarch() {}
|
||||
|
||||
GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) {
|
||||
explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||
uint8_t mux = 1) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient() {}
|
||||
|
||||
bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
@@ -84,64 +77,57 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+SQNSH="), mux);
|
||||
sock_connected = false;
|
||||
at->waitResponse();
|
||||
}
|
||||
|
||||
virtual void stop() { stop(15000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED;
|
||||
|
||||
private:
|
||||
TinyGsmSequansMonarch* at;
|
||||
uint8_t mux;
|
||||
uint16_t sock_available;
|
||||
uint32_t prev_check;
|
||||
bool sock_connected;
|
||||
bool got_data;
|
||||
RxFifo rx;
|
||||
};
|
||||
|
||||
class GsmClientSecure : public GsmClient {
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch {
|
||||
public:
|
||||
GsmClientSecureSequansMonarch() {}
|
||||
|
||||
GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
virtual ~GsmClientSecure() {}
|
||||
explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem,
|
||||
uint8_t mux = 1)
|
||||
: GsmClientSequansMonarch(modem, mux) {}
|
||||
|
||||
protected:
|
||||
bool strictSSL = false;
|
||||
|
||||
public:
|
||||
virtual int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -171,33 +157,27 @@ public:
|
||||
void setStrictSSL(bool strict) {
|
||||
strictSSL = strict;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
TinyGsmSequansMonarch(Stream& stream) : stream(stream) {
|
||||
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,54 +189,32 @@ 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->sock_available = modemGetAvailable(mux);
|
||||
@@ -264,78 +222,54 @@ TINY_GSM_MODEM_TEST_AT()
|
||||
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,114 +325,80 @@ 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,
|
||||
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 getTemperature() {
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -538,7 +406,7 @@ 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 startMillis = millis();
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
|
||||
if (ssl) {
|
||||
@@ -554,22 +422,26 @@ protected:
|
||||
// Socket configuration
|
||||
// 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++) {
|
||||
@@ -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();
|
||||
@@ -732,14 +596,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -779,9 +643,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_
|
||||
|
@@ -6,32 +6,23 @@
|
||||
* @date Nov 2016
|
||||
*/
|
||||
|
||||
#ifndef TinyGsmClientUBLOX_h
|
||||
#define TinyGsmClientUBLOX_h
|
||||
#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_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_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,26 +31,25 @@ 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>;
|
||||
|
||||
/*
|
||||
* Inner Client
|
||||
*/
|
||||
public:
|
||||
|
||||
class GsmClient : public Client
|
||||
{
|
||||
class GsmClientUBLOX : public GsmClient {
|
||||
friend class TinyGsmUBLOX;
|
||||
typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo;
|
||||
|
||||
public:
|
||||
GsmClient() {}
|
||||
GsmClientUBLOX() {}
|
||||
|
||||
GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) {
|
||||
explicit GsmClientUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0) {
|
||||
init(&modem, mux);
|
||||
}
|
||||
|
||||
virtual ~GsmClient(){}
|
||||
|
||||
bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) {
|
||||
this->at = modem;
|
||||
this->mux = mux;
|
||||
@@ -74,7 +64,7 @@ public:
|
||||
}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -90,56 +80,46 @@ public:
|
||||
|
||||
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_CONNECT_OVERLOADS()
|
||||
|
||||
virtual void stop(uint32_t maxWaitMs) {
|
||||
TINY_GSM_CLIENT_DUMP_MODEM_BUFFER()
|
||||
void stop(uint32_t maxWaitMs) {
|
||||
dumpModemBuffer(maxWaitMs);
|
||||
at->sendAT(GF("+USOCL="), mux);
|
||||
at->waitResponse(); // should return within 1s
|
||||
sock_connected = false;
|
||||
}
|
||||
|
||||
virtual void stop() { stop(15000L); }
|
||||
|
||||
TINY_GSM_CLIENT_WRITE()
|
||||
|
||||
TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK()
|
||||
|
||||
TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED()
|
||||
void stop() override {
|
||||
stop(15000L);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended API
|
||||
*/
|
||||
|
||||
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
|
||||
{
|
||||
/*
|
||||
* Inner Secure Client
|
||||
*/
|
||||
public:
|
||||
GsmClientSecure() {}
|
||||
class GsmClientSecureUBLOX : public GsmClientUBLOX {
|
||||
public:
|
||||
GsmClientSecureUBLOX() {}
|
||||
|
||||
GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1)
|
||||
: GsmClient(modem, mux)
|
||||
{}
|
||||
|
||||
virtual ~GsmClientSecure(){}
|
||||
explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 1)
|
||||
: GsmClientUBLOX(modem, mux) {}
|
||||
|
||||
public:
|
||||
virtual int connect(const char *host, uint16_t port, int timeout_s) {
|
||||
int connect(const char* host, uint16_t port, int timeout_s) {
|
||||
stop();
|
||||
TINY_GSM_YIELD();
|
||||
rx.clear();
|
||||
@@ -155,12 +135,11 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Constructor
|
||||
*/
|
||||
public:
|
||||
|
||||
TinyGsmUBLOX(Stream& stream)
|
||||
: stream(stream)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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
|
||||
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
|
||||
@@ -394,9 +316,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK()
|
||||
// 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,7 +329,8 @@ 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
|
||||
// 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
|
||||
@@ -424,106 +348,77 @@ 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 "";
|
||||
}
|
||||
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();
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* GPS location functions
|
||||
*/
|
||||
public:
|
||||
// No functions of this type supported
|
||||
|
||||
/*
|
||||
* Time functions
|
||||
*/
|
||||
protected:
|
||||
// Can follow the standard CCLK function in the template
|
||||
|
||||
/*
|
||||
* Battery & temperature functions
|
||||
*/
|
||||
protected:
|
||||
uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE;
|
||||
|
||||
uint16_t getBattVoltage() 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
|
||||
@@ -532,30 +427,30 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED()
|
||||
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;
|
||||
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:
|
||||
|
||||
bool modemConnect(const char* host, uint16_t port, uint8_t* mux,
|
||||
bool ssl = false, int timeout_s = 120)
|
||||
{
|
||||
bool ssl = false, int timeout_s = 120) {
|
||||
uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000;
|
||||
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();
|
||||
@@ -582,16 +477,12 @@ 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;
|
||||
}
|
||||
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
|
||||
@@ -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;
|
||||
}
|
||||
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);
|
||||
@@ -630,9 +517,7 @@ protected:
|
||||
// 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,8 +526,7 @@ 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
|
||||
@@ -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();
|
||||
@@ -684,14 +565,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/
|
||||
data.reserve(64);
|
||||
int index = 0;
|
||||
unsigned long startMillis = millis();
|
||||
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;
|
||||
@@ -732,9 +613,7 @@ TINY_GSM_MODEM_STREAM_UTILITIES()
|
||||
finish:
|
||||
if (!index) {
|
||||
data.trim();
|
||||
if (data.length()) {
|
||||
DBG("### Unhandled:", data);
|
||||
}
|
||||
if (data.length()) { DBG("### Unhandled:", data); }
|
||||
data = "";
|
||||
}
|
||||
// data.replace(GSM_NL, "/");
|
||||
@@ -742,25 +621,25 @@ finish:
|
||||
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];
|
||||
Stream& stream;
|
||||
GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT];
|
||||
const char* gsmNL = GSM_NL;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif // SRC_TINYGSMCLIENTUBLOX_H_
|
||||
|
File diff suppressed because it is too large
Load Diff
1490
src/TinyGsmCommon.h
1490
src/TinyGsmCommon.h
File diff suppressed because it is too large
Load Diff
@@ -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();
|
||||
}
|
||||
|
Reference in New Issue
Block a user