CRTP!!!! Totally untested

Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
This commit is contained in:
Sara Damiano
2020-02-06 15:20:44 -05:00
parent 7d6aba266c
commit d3d1083d8f
31 changed files with 5359 additions and 6794 deletions

View File

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