mirror of
				https://github.com/KevinMidboe/TinyGSM.git
				synced 2025-10-29 18:00:18 +00:00 
			
		
		
		
	CRTP!!!! Totally untested
Signed-off-by: Sara Damiano <sdamiano@stroudcenter.org>
This commit is contained in:
		| @@ -6,31 +6,23 @@ | ||||
|  * @date       Apr 2018 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientBG96_h | ||||
| #define TinyGsmClientBG96_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientBG96") | ||||
| #ifndef SRC_TINYGSMCLIENTBG96_H_ | ||||
| #define SRC_TINYGSMCLIENTBG96_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientBG96") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 12 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,474 +31,303 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmBG96: public TinyGsmUTFSMS<TinyGsmBG96> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   friend class TinyGsmBG96; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|  | ||||
|   GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) { | ||||
|     init(&modem, mux); | ||||
|   } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|   bool init(TinyGsmBG96* modem, uint8_t mux = 1) { | ||||
|     this->at = modem; | ||||
|     this->mux = mux; | ||||
|     sock_available = 0; | ||||
|     prev_check = 0; | ||||
|     sock_connected = false; | ||||
|     got_data = false; | ||||
|  | ||||
|     at->sockets[mux] = this; | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|     stop(); | ||||
|     TINY_GSM_YIELD(); | ||||
|     rx.clear(); | ||||
|     sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|     return sock_connected; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     at->sendAT(GF("+QICLOSE="), mux); | ||||
|     sock_connected = false; | ||||
|     at->waitResponse(); | ||||
|   } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
| 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>; | ||||
|  | ||||
|   /* | ||||
|    * Extended API | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientBG96 : public GsmClient { | ||||
|     friend class TinyGsmBG96; | ||||
|  | ||||
|    public: | ||||
|     GsmClientBG96() {} | ||||
|  | ||||
|     explicit GsmClientBG96(TinyGsmBG96& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|     bool init(TinyGsmBG96* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
|       sock_available = 0; | ||||
|       prev_check     = 0; | ||||
|       sock_connected = false; | ||||
|       got_data       = false; | ||||
|  | ||||
|       at->sockets[mux] = this; | ||||
|  | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|    public: | ||||
|     virtual int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+QICLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(); | ||||
|     } | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|   String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
| private: | ||||
|   TinyGsmBG96*    at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|  | ||||
|  | ||||
| // class GsmClientSecure : public GsmClient | ||||
| // { | ||||
| // public: | ||||
| //   GsmClientSecure() {} | ||||
| // | ||||
| //   GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1) | ||||
| //     : GsmClient(modem, mux) | ||||
| //   {} | ||||
| // | ||||
| //   virtual ~GsmClientSecure(){} | ||||
| // | ||||
| // public: | ||||
| //   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
| //     stop(); | ||||
| //     TINY_GSM_YIELD(); | ||||
| //     rx.clear(); | ||||
| //     sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
| //     return sock_connected; | ||||
| //   } | ||||
| // }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmBG96(Stream& stream) | ||||
|     : stream(stream) | ||||
|   /* | ||||
|   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; | ||||
|     } | ||||
|   }; | ||||
|   */ | ||||
|  | ||||
|   /* | ||||
|    * 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; | ||||
|     } | ||||
|     // Configure the TCPIP Context | ||||
|     sendAT(GF("+QICSGP=1,1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, | ||||
|            GF("\"")); | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Activate GPRS/CSD Context | ||||
|     // Activate GPRS/CSD Context | ||||
|     sendAT(GF("+QIACT=1")); | ||||
|     if (waitResponse(150000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(150000L) != 1) { return false; } | ||||
|  | ||||
|     //Attach to Packet Domain service - is this necessary? | ||||
|     // Attach to Packet Domain service - is this necessary? | ||||
|     sendAT(GF("+CGATT=1")); | ||||
|     if (waitResponse(60000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|   bool gprsDisconnectImpl() { | ||||
|     sendAT(GF("+QIDEACT=1"));  // Deactivate the bearer context | ||||
|     if (waitResponse(40000L) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(40000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|     sendAT(GF("+CGPADDR=1")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     streamSkipUntil(',');  // Skip context id | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  protected: | ||||
|   // Can follow all of the IP functions from the template | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() { | ||||
|     sendAT(GF("A")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   // Returns true on pick-up, false on error/busy | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callHangup() { | ||||
|     sendAT(GF("H")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   // 0-9,*,#,A,B,C,D | ||||
|   bool dtmfSend(char cmd, int duration_ms = 100) { // TODO: check | ||||
|     duration_ms = constrain(duration_ms, 100, 1000); | ||||
|  | ||||
|     sendAT(GF("+VTD="), duration_ms / 100); // VTD accepts in 1/10 of a second | ||||
|     waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+VTS="), cmd); | ||||
|     return waitResponse(10000L) == 1; | ||||
|   } | ||||
|  protected: | ||||
|   // Can follow all of the phone call functions from the template | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   // Follows all messaging functions per template | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  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!"); } | ||||
|     int      rsp; | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|  | ||||
| protected: | ||||
|     // <PDPcontextID>(1-16), <connectID>(0-11), | ||||
|     // "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>", | ||||
|     // <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer) | ||||
|     sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host, | ||||
|            GF("\","), port, GF(",0,0")); | ||||
|     waitResponse(); | ||||
|  | ||||
|  bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                    bool ssl = false, int timeout_s = 20) { | ||||
|    if (ssl) { | ||||
|      DBG("SSL not yet supported on this module!"); | ||||
|    } | ||||
|    int rsp; | ||||
|    uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; } | ||||
|  | ||||
|     // <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE", | ||||
|     // "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer) | ||||
|     sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0")); | ||||
|     rsp = waitResponse(); | ||||
|  | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     if (stream.readStringUntil(',').toInt() != mux) { | ||||
|       return false; | ||||
|     } | ||||
|     if (stream.readStringUntil(',').toInt() != mux) { return false; } | ||||
|     // Read status | ||||
|     rsp = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
| @@ -515,28 +336,20 @@ protected: | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     // TODO: Wait for ACK? AT+QISEND=id,0 | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } | ||||
|     // TODO(?): Wait for ACK? AT+QISEND=id,0 | ||||
|     return len; | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     sendAT(GF("+QIRD="), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+QIRD:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+QIRD:")) != 1) { return 0; } | ||||
|     int len = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     for (int i=0; i<len; i++) { | ||||
|       TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|     } | ||||
|     for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } | ||||
|     waitResponse(); | ||||
|     DBG("### READ:", len, "from", mux); | ||||
|     sockets[mux]->sock_available = modemGetAvailable(mux); | ||||
| @@ -547,33 +360,28 @@ protected: | ||||
|     sendAT(GF("+QIRD="), mux, GF(",0")); | ||||
|     size_t result = 0; | ||||
|     if (waitResponse(GF("+QIRD:")) == 1) { | ||||
|       streamSkipUntil(','); // Skip total received | ||||
|       streamSkipUntil(','); // Skip have read | ||||
|       streamSkipUntil(',');  // Skip total received | ||||
|       streamSkipUntil(',');  // Skip have read | ||||
|       result = stream.readStringUntil('\n').toInt(); | ||||
|       if (result) { | ||||
|         DBG("### DATA AVAILABLE:", result, "on", mux); | ||||
|       } | ||||
|       if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); } | ||||
|       waitResponse(); | ||||
|     } | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     sendAT(GF("+QISTATE=1,"), mux); | ||||
|     //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|     // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|  | ||||
|     if (waitResponse(GF("+QISTATE:")) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(GF("+QISTATE:")) != 1) { return false; } | ||||
|  | ||||
|     streamSkipUntil(','); // Skip mux | ||||
|     streamSkipUntil(','); // Skip socket type | ||||
|     streamSkipUntil(','); // Skip remote ip | ||||
|     streamSkipUntil(','); // Skip remote port | ||||
|     streamSkipUntil(','); // Skip local port | ||||
|     int res = stream.readStringUntil(',').toInt(); // socket state | ||||
|     streamSkipUntil(',');                           // Skip mux | ||||
|     streamSkipUntil(',');                           // Skip socket type | ||||
|     streamSkipUntil(',');                           // Skip remote ip | ||||
|     streamSkipUntil(',');                           // Skip remote port | ||||
|     streamSkipUntil(',');                           // Skip local port | ||||
|     int res = stream.readStringUntil(',').toInt();  // socket state | ||||
|  | ||||
|     waitResponse(); | ||||
|  | ||||
| @@ -581,19 +389,16 @@ protected: | ||||
|     return 2 == res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -601,15 +406,15 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     String r5s(r5); r5s.trim(); | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int index = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     int      index       = 0; | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue; // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -648,38 +453,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|   Stream&       stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|  protected: | ||||
|   Stream&        stream; | ||||
|   GsmClientBG96* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*    gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTBG96_H_ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user