mirror of
				https://github.com/KevinMidboe/TinyGSM.git
				synced 2025-10-29 18:00:18 +00:00 
			
		
		
		
	Merge branch 'shajek-master'
This commit is contained in:
		| @@ -41,13 +41,19 @@ | |||||||
|   // typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO! |   // typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO! | ||||||
|  |  | ||||||
| #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ | #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ | ||||||
|       defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) || \ |       defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) | ||||||
|       defined(TINY_GSM_MODEM_SIM7500) || defined(TINY_GSM_MODEM_SIM7600) |  | ||||||
|   #define TINY_GSM_MODEM_HAS_GPRS |   #define TINY_GSM_MODEM_HAS_GPRS | ||||||
|   #include <TinyGsmClientSIM5360.h> |   #include <TinyGsmClientSIM5360.h> | ||||||
|   typedef TinyGsmSim5360 TinyGsm; |   typedef TinyGsmSim5360 TinyGsm; | ||||||
|   typedef TinyGsmSim5360::GsmClient TinyGsmClient; |   typedef TinyGsmSim5360::GsmClient TinyGsmClient; | ||||||
|  |  | ||||||
|  | #elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \ | ||||||
|  |     defined(TINY_GSM_MODEM_SIM7500) | ||||||
|  |   #define TINY_GSM_MODEM_HAS_GPRS | ||||||
|  |   #include <TinyGsmClientSIM7600.h> | ||||||
|  |   typedef TinyGsmSim7600 TinyGsm; | ||||||
|  |   typedef TinyGsmSim7600::GsmClient TinyGsmClient; | ||||||
|  |  | ||||||
| #elif defined(TINY_GSM_MODEM_UBLOX) | #elif defined(TINY_GSM_MODEM_UBLOX) | ||||||
|   #define TINY_GSM_MODEM_HAS_GPRS |   #define TINY_GSM_MODEM_HAS_GPRS | ||||||
|   #define TINY_GSM_MODEM_HAS_SSL |   #define TINY_GSM_MODEM_HAS_SSL | ||||||
|   | |||||||
| @@ -58,13 +58,13 @@ class GsmClient : public Client | |||||||
| public: | public: | ||||||
|   GsmClient() {} |   GsmClient() {} | ||||||
|  |  | ||||||
|   GsmClient(TinyGsmSim5360& modem, uint8_t mux = 1) { |   GsmClient(TinyGsmSim5360& modem, uint8_t mux = 0) { | ||||||
|     init(&modem, mux); |     init(&modem, mux); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   virtual ~GsmClient(){} |   virtual ~GsmClient(){} | ||||||
|  |  | ||||||
|   bool init(TinyGsmSim5360* modem, uint8_t mux = 1) { |   bool init(TinyGsmSim5360* modem, uint8_t mux = 0) { | ||||||
|     this->at = modem; |     this->at = modem; | ||||||
|     this->mux = mux; |     this->mux = mux; | ||||||
|     sock_available = 0; |     sock_available = 0; | ||||||
| @@ -324,7 +324,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|       waitResponse(); |       waitResponse(); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Define PDP context 1 |     // Define external PDP context 1 | ||||||
|     sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"',",\"0.0.0.0\",0,0"); |     sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"',",\"0.0.0.0\",0,0"); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |  | ||||||
| @@ -399,24 +399,12 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Stop the socket service |     // Stop the socket service | ||||||
|     // Note: all sockets should be closed first |     // Note: all sockets should be closed first - on 3G/4G models the sockets must be closed manually | ||||||
|     sendAT(GF("+NETCLOSE")); |     sendAT(GF("+NETCLOSE")); | ||||||
|     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { |     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // Deactivate PDP context 1 |  | ||||||
|     sendAT(GF("+CGACT=1,0")); |  | ||||||
|     if (waitResponse(40000L) != 1) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Detach from GPRS |  | ||||||
|     sendAT(GF("+CGATT=0")); |  | ||||||
|     if (waitResponse(360000L) != 1) { |  | ||||||
|       return false; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -473,8 +461,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|    */ |    */ | ||||||
|  |  | ||||||
|   String sendUSSD(const String& code) { |   String sendUSSD(const String& code) { | ||||||
|  |     // Select message format (1=text) | ||||||
|     sendAT(GF("+CMGF=1")); |     sendAT(GF("+CMGF=1")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Select TE character set | ||||||
|     sendAT(GF("+CSCS=\"HEX\"")); |     sendAT(GF("+CSCS=\"HEX\"")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\"")); |     sendAT(GF("+CUSD=1,\""), code, GF("\"")); | ||||||
| @@ -499,14 +489,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   bool sendSMS(const String& number, const String& text) { |   bool sendSMS(const String& number, const String& text) { | ||||||
|  |     // Get SMS service centre address | ||||||
|     sendAT(GF("+AT+CSCA?")); |     sendAT(GF("+AT+CSCA?")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Select message format (1=text) | ||||||
|     sendAT(GF("+CMGF=1")); |     sendAT(GF("+CMGF=1")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) |     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||||
|     sendAT(GF("+CSCS=\"GSM\"")); |     sendAT(GF("+CSCS=\"GSM\"")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Send the message! | ||||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); |     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||||
|     if (waitResponse(GF(">")) != 1) { |     if (waitResponse(GF(">")) != 1) { | ||||||
|       return false; |       return false; | ||||||
| @@ -518,13 +510,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   bool sendSMS_UTF16(const String& number, const void* text, size_t len) { |   bool sendSMS_UTF16(const String& number, const void* text, size_t len) { | ||||||
|  |     // Select message format (1=text) | ||||||
|     sendAT(GF("+CMGF=1")); |     sendAT(GF("+CMGF=1")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Select TE character set | ||||||
|     sendAT(GF("+CSCS=\"HEX\"")); |     sendAT(GF("+CSCS=\"HEX\"")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Set text mode parameters | ||||||
|     sendAT(GF("+CSMP=17,167,0,8")); |     sendAT(GF("+CSMP=17,167,0,8")); | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Send the message | ||||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); |     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||||
|     if (waitResponse(GF(">")) != 1) { |     if (waitResponse(GF(">")) != 1) { | ||||||
|       return false; |       return false; | ||||||
| @@ -571,10 +566,12 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|     } |     } | ||||||
|     streamSkipUntil(','); // Skip battery charge status |     streamSkipUntil(','); // Skip battery charge status | ||||||
|     streamSkipUntil(','); // Skip battery charge level |     streamSkipUntil(','); // Skip battery charge level | ||||||
|     // return voltage in mV |     // get voltage in VOLTS | ||||||
|     uint16_t res = stream.readStringUntil(',').toInt(); |     float voltage = stream.readStringUntil('\n').toFloat(); | ||||||
|     // Wait for final OK |     // Wait for final OK | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|  |     // Return millivolts | ||||||
|  | 	uint16_t res = voltage*1000; | ||||||
|     return res; |     return res; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -610,17 +607,31 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | |||||||
|     } |     } | ||||||
|     chargeState = stream.readStringUntil(',').toInt(); |     chargeState = stream.readStringUntil(',').toInt(); | ||||||
|     percent = stream.readStringUntil(',').toInt(); |     percent = stream.readStringUntil(',').toInt(); | ||||||
|     milliVolts = stream.readStringUntil('\n').toInt(); |     // get voltage in VOLTS | ||||||
|  |     float voltage = stream.readStringUntil('\n').toFloat(); | ||||||
|  |     milliVolts = voltage*1000; | ||||||
|     // Wait for final OK |     // Wait for final OK | ||||||
|     waitResponse(); |     waitResponse(); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; |   // get temperature in degree celsius | ||||||
|     // ToDo: |   float getTemperature() { | ||||||
|     // # Enable Temparature Reading: |     // Enable Temparature Reading | ||||||
|     //AT+CMTE=1 |     sendAT(GF("+CMTE=1")); | ||||||
|     //AT+CMTE? |     if (waitResponse() != 1) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     // Get Temparature Value | ||||||
|  |     sendAT(GF("+CMTE?")); | ||||||
|  |     if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     float res = stream.readStringUntil('\n').toFloat(); | ||||||
|  |     // Wait for final OK | ||||||
|  |     waitResponse(); | ||||||
|  |     return res; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /* |   /* | ||||||
|    * Client related functions |    * Client related functions | ||||||
| @@ -636,9 +647,9 @@ protected: | |||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|         // Establish a connection in multi-socket mode |     // Establish a connection in multi-socket mode | ||||||
|     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 |     // The reply is +CIPOPEN: ## of socket created | ||||||
|     if (waitResponse(15000L, GF(GSM_NL "+CIPOPEN:")) != 1) { |     if (waitResponse(15000L, GF(GSM_NL "+CIPOPEN:")) != 1) { | ||||||
|       return false; |       return false; | ||||||
|     } |     } | ||||||
| @@ -693,7 +704,6 @@ protected: | |||||||
| #endif | #endif | ||||||
|       sockets[mux]->rx.put(c); |       sockets[mux]->rx.put(c); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     DBG("### READ:", len_requested, "from", mux); |     DBG("### READ:", len_requested, "from", mux); | ||||||
|     // sockets[mux]->sock_available = modemGetAvailable(mux); |     // sockets[mux]->sock_available = modemGetAvailable(mux); | ||||||
|     sockets[mux]->sock_available = len_confirmed; |     sockets[mux]->sock_available = len_confirmed; | ||||||
| @@ -719,9 +729,10 @@ protected: | |||||||
|  |  | ||||||
|   bool modemGetConnected(uint8_t mux) { |   bool modemGetConnected(uint8_t mux) { | ||||||
|     // Read the status of all sockets at once |     // Read the status of all sockets at once | ||||||
|     sendAT(GF("+CIPCLOSE?"), mux); |     sendAT(GF("+CIPCLOSE?")); | ||||||
|     if (waitResponse(GFP(GSM_OK), GF("+CIPCLOSE: ")) != 2) |     if (waitResponse(GF("+CIPCLOSE:")) != 1) { | ||||||
|       return false; |       return false; | ||||||
|  |     } | ||||||
|     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> |       // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state> | ||||||
|       sockets[muxNo]->sock_connected = stream.parseInt(); |       sockets[muxNo]->sock_connected = stream.parseInt(); | ||||||
|   | |||||||
							
								
								
									
										873
									
								
								src/TinyGsmClientSIM7600.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										873
									
								
								src/TinyGsmClientSIM7600.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,873 @@ | |||||||
|  | /** | ||||||
|  |  * @file       TinyGsmClientSIM7600.h | ||||||
|  |  * @author     Volodymyr Shymanskyy | ||||||
|  |  * @license    LGPL-3.0 | ||||||
|  |  * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy | ||||||
|  |  * @date       Nov 2016 | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | #ifndef TinyGsmClientSIM7600_h | ||||||
|  | #define 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> | ||||||
|  |  | ||||||
|  | #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, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum RegStatus { | ||||||
|  |   REG_UNREGISTERED = 0, | ||||||
|  |   REG_SEARCHING    = 2, | ||||||
|  |   REG_DENIED       = 3, | ||||||
|  |   REG_OK_HOME      = 1, | ||||||
|  |   REG_OK_ROAMING   = 5, | ||||||
|  |   REG_UNKNOWN      = 4, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum TinyGSMDateTimeFormat { | ||||||
|  |   DATE_FULL = 0, | ||||||
|  |   DATE_TIME = 1, | ||||||
|  |   DATE_DATE = 2 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class TinyGsmSim7600 | ||||||
|  | { | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  | class GsmClient : public Client | ||||||
|  | { | ||||||
|  |   friend class TinyGsmSim7600; | ||||||
|  |   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   GsmClient() {} | ||||||
|  |  | ||||||
|  |   GsmClient(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; | ||||||
|  |     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("+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() | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * 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; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   TinyGsmSim7600(Stream& stream) | ||||||
|  |     : stream(stream) | ||||||
|  |   { | ||||||
|  |     memset(sockets, 0, sizeof(sockets)); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   virtual ~TinyGsmSim7600(){} | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Basic functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   bool begin(const char* pin = NULL) { | ||||||
|  |     return init(pin); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool init(const char* pin = NULL) { | ||||||
|  |     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||||
|  |     if (!testAT()) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     sendAT(GF("E0"));   // Echo Off | ||||||
|  |     if (waitResponse() != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     DBG(GF("### Modem:"), getModemName()); | ||||||
|  |     getSimStatus(); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String getModemName() { | ||||||
|  |     String name =  "SIMCom SIM7600"; | ||||||
|  |  | ||||||
|  |     sendAT(GF("+CGMM")); | ||||||
|  |     String res2; | ||||||
|  |     if (waitResponse(1000L, res2) != 1) { | ||||||
|  |       return name; | ||||||
|  |     } | ||||||
|  |     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||||
|  |     res2.replace("_", " "); | ||||||
|  |     res2.trim(); | ||||||
|  |  | ||||||
|  |     name = res2; | ||||||
|  |     DBG("### Modem:", name); | ||||||
|  |     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 | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | TINY_GSM_MODEM_GET_INFO_ATI() | ||||||
|  |  | ||||||
|  |   bool hasSSL() { | ||||||
|  |     return false;  // TODO:  Module supports SSL, but not yet implemented | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool hasWifi() { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool hasGPRS() { | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Power functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   bool restart() { | ||||||
|  |     if (!testAT()) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     sendAT(GF("+CRESET")); | ||||||
|  |     if (waitResponse(10000L) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     delay(5000L);  // TODO:  Test this delay! | ||||||
|  |     return init(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool poweroff() { | ||||||
|  |     sendAT(GF("+CPOF")); | ||||||
|  |     return waitResponse() == 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool radioOff() { | ||||||
|  |     sendAT(GF("+CFUN=4")); | ||||||
|  |     if (waitResponse(10000L) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     delay(3000); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool sleepEnable(bool enable = true) { | ||||||
|  |     sendAT(GF("+CSCLK="), enable); | ||||||
|  |     return waitResponse() == 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * SIM card functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  | TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||||
|  |  | ||||||
|  | // Gets the CCID of a sim card via AT+CCID | ||||||
|  |   String getSimCCID() { | ||||||
|  |     sendAT(GF("+CICCID")); | ||||||
|  |     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 | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  | TINY_GSM_MODEM_GET_CSQ() | ||||||
|  |  | ||||||
|  |   bool isNetworkConnected() { | ||||||
|  |     RegStatus s = getRegistrationStatus(); | ||||||
|  |     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   String getNetworkModes() { | ||||||
|  |     sendAT(GF("+CNMP=?")); | ||||||
|  |     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"; | ||||||
|  |       } | ||||||
|  |     String res = stream.readStringUntil('\n'); | ||||||
|  |     waitResponse(); | ||||||
|  |     return res; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * GPRS functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||||
|  |     gprsDisconnect();  // Make sure we're not connected first | ||||||
|  |  | ||||||
|  |     // Define the PDP context | ||||||
|  |  | ||||||
|  |     // The CGDCONT commands set up the "external" PDP context | ||||||
|  |  | ||||||
|  |     // Set the external authentication | ||||||
|  |     if (user && strlen(user) > 0) { | ||||||
|  |       sendAT(GF("+CGAUTH=1,0,\""), user, GF("\",\""), pwd, '"'); | ||||||
|  |       waitResponse(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Define external PDP context 1 | ||||||
|  |     sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"',",\"0.0.0.0\",0,0"); | ||||||
|  |     waitResponse(); | ||||||
|  |  | ||||||
|  |     // Configure TCP parameters | ||||||
|  |  | ||||||
|  |     // Select TCP/IP application mode (command mode) | ||||||
|  |     sendAT(GF("+CIPMODE=0")); | ||||||
|  |     waitResponse(); | ||||||
|  |  | ||||||
|  |     // Set Sending Mode - send without waiting for peer TCP ACK | ||||||
|  |     sendAT(GF("+CIPSENDMODE=0")); | ||||||
|  |     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) | ||||||
|  |     // 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) | ||||||
|  |     // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 | ||||||
|  |     sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); | ||||||
|  |     if (waitResponse() != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Configure timeouts for opening and closing sockets | ||||||
|  |     // AT+CIPTIMEOUT=[<netopen_timeout>][, [<cipopen_timeout>][, [<cipsend_timeout>]]] | ||||||
|  |     sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); | ||||||
|  |     waitResponse(); | ||||||
|  |  | ||||||
|  |     // Start the socket service | ||||||
|  |  | ||||||
|  |     // This activates and attaches to the external PDP context that is tied | ||||||
|  |     // to the embedded context for TCP/IP (ie AT+CGACT=1,1 and AT+CGATT=1) | ||||||
|  |     // Response may be an immediate "OK" followed later by "+NETOPEN: 0". | ||||||
|  |     // 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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool gprsDisconnect() { | ||||||
|  |  | ||||||
|  |     // Close all sockets and stop the socket 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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool isGprsConnected() { | ||||||
|  |     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; | ||||||
|  |     } | ||||||
|  |     waitResponse(); | ||||||
|  |  | ||||||
|  |     sendAT(GF("+IPADDR")); // Inquire Socket PDP address | ||||||
|  |     // sendAT(GF("+CGPADDR=1")); // Show PDP address | ||||||
|  |     if (waitResponse() != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * IP Address functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   String getLocalIP() { | ||||||
|  |     sendAT(GF("+IPADDR"));  // Inquire Socket PDP address | ||||||
|  |     // sendAT(GF("+CGPADDR=1"));  // Show PDP address | ||||||
|  |     String res; | ||||||
|  |     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; | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * 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; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool sendSMS_UTF16(const String& number, const void* text, size_t len) { | ||||||
|  |     // Select message format (1=text) | ||||||
|  |     sendAT(GF("+CMGF=1")); | ||||||
|  |     waitResponse(); | ||||||
|  |     // Select TE character set | ||||||
|  |     sendAT(GF("+CSCS=\"HEX\"")); | ||||||
|  |     waitResponse(); | ||||||
|  |     // Set text mode parameters | ||||||
|  |     sendAT(GF("+CSMP=17,167,0,8")); | ||||||
|  |     waitResponse(); | ||||||
|  |     // Send the message | ||||||
|  |     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||||
|  |     if (waitResponse(GF(">")) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     uint16_t* t = (uint16_t*)text; | ||||||
|  |     for (size_t i=0; i<len; i++) { | ||||||
|  |       uint8_t c = t[i] >> 8; | ||||||
|  |       if (c < 0x10) { stream.print('0'); } | ||||||
|  |       stream.print(c, HEX); | ||||||
|  |       c = t[i] & 0xFF; | ||||||
|  |       if (c < 0x10) { stream.print('0'); } | ||||||
|  |       stream.print(c, HEX); | ||||||
|  |     } | ||||||
|  |     stream.write((char)0x1A); | ||||||
|  |     stream.flush(); | ||||||
|  |     return waitResponse(60000L) == 1; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Location functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   String getGsmLocation()  TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * GPS location functions | ||||||
|  |    */ | ||||||
|  |   // enable GPS | ||||||
|  |   bool enableGPS() { | ||||||
|  |     sendAT(GF("+CGPS=1")); | ||||||
|  |     if (waitResponse() != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   bool disableGPS() { | ||||||
|  |     sendAT(GF("+CGPS=0")); | ||||||
|  |     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 ""; | ||||||
|  |     } | ||||||
|  |     String res = stream.readStringUntil('\n'); | ||||||
|  |     waitResponse(); | ||||||
|  |     res.trim(); | ||||||
|  |     return res; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // get GPS informations | ||||||
|  |   bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) { | ||||||
|  |     //String buffer = ""; | ||||||
|  |     bool fix = false; | ||||||
|  |  | ||||||
|  |     sendAT(GF("+CGNSSINFO")); | ||||||
|  |     if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     //stream.readStringUntil(','); // mode | ||||||
|  |     if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; | ||||||
|  |     stream.readStringUntil(','); //gps | ||||||
|  | 	stream.readStringUntil(','); // glonass | ||||||
|  | 	stream.readStringUntil(','); // beidu | ||||||
|  |     *lat =  stream.readStringUntil(',').toFloat(); //lat | ||||||
|  | 	stream.readStringUntil(','); // N/S | ||||||
|  |     *lon =  stream.readStringUntil(',').toFloat(); //lon | ||||||
|  | 	stream.readStringUntil(','); // E/W | ||||||
|  | 	stream.readStringUntil(','); // date | ||||||
|  | 	stream.readStringUntil(','); // UTC time | ||||||
|  |     if (alt != NULL) *alt =  stream.readStringUntil(',').toFloat(); //alt | ||||||
|  |     if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed | ||||||
|  |     stream.readStringUntil(','); //course | ||||||
|  |     stream.readStringUntil(','); //time | ||||||
|  |     stream.readStringUntil(',');//PDOP | ||||||
|  |     stream.readStringUntil(',');//HDOP | ||||||
|  |     stream.readStringUntil(',');//VDOP | ||||||
|  |     //if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites | ||||||
|  |     //if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites | ||||||
|  |     stream.readStringUntil('\n'); | ||||||
|  |  | ||||||
|  |     waitResponse(); | ||||||
|  |  | ||||||
|  |     return fix; | ||||||
|  |   } | ||||||
|  |   /* | ||||||
|  |    * Time functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * 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; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // get voltage in VOLTS | ||||||
|  |     float voltage = stream.readStringUntil('\n').toFloat(); | ||||||
|  |     // Wait for final OK | ||||||
|  |     waitResponse(); | ||||||
|  |     // Return millivolts | ||||||
|  | 	uint16_t res = voltage*1000; | ||||||
|  |     return res; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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) { | ||||||
|  |     sendAT(GF("+CBC?")); | ||||||
|  |     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |     // get voltage in VOLTS | ||||||
|  |     float voltage = stream.readStringUntil('\n').toFloat(); | ||||||
|  |     milliVolts = voltage*1000; | ||||||
|  |     // Wait for final OK | ||||||
|  |     waitResponse(); | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // get temperature in degree celsius | ||||||
|  |   uint16_t getTemperature() { | ||||||
|  |     sendAT(GF("+CPMUTEMP")); | ||||||
|  |     if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     // return temperature in C | ||||||
|  |     uint16_t res = stream.readStringUntil('\n').toInt(); | ||||||
|  |     // Wait for final OK | ||||||
|  |     waitResponse(); | ||||||
|  |     return res; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    * Client related functions | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |  | ||||||
|  |   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||||
|  |                     bool ssl = false, int timeout_s = 75) { | ||||||
|  |     // Make sure we'll be getting data manually on this connection | ||||||
|  |     sendAT(GF("+CIPRXGET=1")); | ||||||
|  |     if (waitResponse() != 1) { | ||||||
|  |       return false; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Establish a connection in multi-socket mode | ||||||
|  |     sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port); | ||||||
|  |     // The reply is +CIPOPEN: ## of socket created | ||||||
|  |     if (waitResponse(15000L, 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, ',', len); | ||||||
|  |     if (waitResponse(GF(">")) != 1) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     stream.write((uint8_t*)buff, len); | ||||||
|  |     stream.flush(); | ||||||
|  |     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 | ||||||
|  |     return stream.readStringUntil('\n').toInt(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   size_t modemRead(size_t size, uint8_t mux) { | ||||||
|  | #ifdef TINY_GSM_USE_HEX | ||||||
|  |     sendAT(GF("+CIPRXGET=3,"), mux, ',', size); | ||||||
|  |     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  | #else | ||||||
|  |     sendAT(GF("+CIPRXGET=2,"), mux, ',', size); | ||||||
|  |     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     streamSkipUntil(','); // Skip Rx mode 2/normal or 3/HEX | ||||||
|  |     streamSkipUntil(','); // Skip mux/cid (connecion id) | ||||||
|  |     size_t len_requested = stream.readStringUntil(',').toInt(); | ||||||
|  |     //  ^^ Requested number of data bytes (1-1460 bytes)to be read | ||||||
|  |     size_t len_confirmed = stream.readStringUntil('\n').toInt(); | ||||||
|  |     // ^^ The data length which not read in the buffer | ||||||
|  |     for (size_t 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, }; | ||||||
|  |       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(); } | ||||||
|  |       char c = stream.read(); | ||||||
|  | #endif | ||||||
|  |       sockets[mux]->rx.put(c); | ||||||
|  |     } | ||||||
|  |     DBG("### READ:", len_requested, "from", mux); | ||||||
|  |     // sockets[mux]->sock_available = modemGetAvailable(mux); | ||||||
|  |     sockets[mux]->sock_available = len_confirmed; | ||||||
|  |     waitResponse(); | ||||||
|  |     return len_requested; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   size_t modemGetAvailable(uint8_t mux) { | ||||||
|  |     sendAT(GF("+CIPRXGET=4,"), mux); | ||||||
|  |     size_t result = 0; | ||||||
|  |     if (waitResponse(GF("+CIPRXGET:")) == 1) { | ||||||
|  |       streamSkipUntil(','); // Skip mode 4 | ||||||
|  |       streamSkipUntil(','); // Skip mux | ||||||
|  |       result = stream.readStringUntil('\n').toInt(); | ||||||
|  |       waitResponse(); | ||||||
|  |     } | ||||||
|  |     DBG("### Available:", result, "on", 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;  // TODO:  Why does this not read correctly? | ||||||
|  |     } | ||||||
|  |     for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { | ||||||
|  |       // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state> | ||||||
|  |       sockets[muxNo]->sock_connected = stream.parseInt(); | ||||||
|  |     } | ||||||
|  |     waitResponse();  // Should be an OK at the end | ||||||
|  |     return sockets[mux]->sock_connected; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |  | ||||||
|  |   /* | ||||||
|  |    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) | ||||||
|  |   { | ||||||
|  |     /*String r1s(r1); r1s.trim(); | ||||||
|  |     String r2s(r2); r2s.trim(); | ||||||
|  |     String r3s(r3); r3s.trim(); | ||||||
|  |     String r4s(r4); r4s.trim(); | ||||||
|  |     String r5s(r5); r5s.trim(); | ||||||
|  |     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||||
|  |     data.reserve(64); | ||||||
|  |     int index = 0; | ||||||
|  |     unsigned long 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 (r1 && data.endsWith(r1)) { | ||||||
|  |           index = 1; | ||||||
|  |           goto finish; | ||||||
|  |         } else if (r2 && data.endsWith(r2)) { | ||||||
|  |           index = 2; | ||||||
|  |           goto finish; | ||||||
|  |         } else if (r3 && data.endsWith(r3)) { | ||||||
|  |           index = 3; | ||||||
|  |           goto finish; | ||||||
|  |         } else if (r4 && data.endsWith(r4)) { | ||||||
|  |           index = 4; | ||||||
|  |           goto finish; | ||||||
|  |         } else if (r5 && data.endsWith(r5)) { | ||||||
|  |           index = 5; | ||||||
|  |           goto finish; | ||||||
|  |         } else if (data.endsWith(GF(GSM_NL "+CIPRXGET:"))) { | ||||||
|  |           String mode = stream.readStringUntil(','); | ||||||
|  |           if (mode.toInt() == 1) { | ||||||
|  |             int mux = stream.readStringUntil('\n').toInt(); | ||||||
|  |             if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||||
|  |               sockets[mux]->got_data = true; | ||||||
|  |             } | ||||||
|  |             data = ""; | ||||||
|  |             DBG("### Got Data:", mux); | ||||||
|  |           } else { | ||||||
|  |             data += mode; | ||||||
|  |           } | ||||||
|  |         } else if (data.endsWith(GF(GSM_NL "+RECEIVE:"))) { | ||||||
|  |           int mux = stream.readStringUntil(',').toInt(); | ||||||
|  |           int len = stream.readStringUntil('\n').toInt(); | ||||||
|  |           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||||
|  |             sockets[mux]->got_data = true; | ||||||
|  |             sockets[mux]->sock_available = len; | ||||||
|  |           } | ||||||
|  |           data = ""; | ||||||
|  |           DBG("### Got Data:", len, "on", mux); | ||||||
|  |         } else if (data.endsWith(GF("+IPCLOSE:"))) { | ||||||
|  |           int mux = stream.readStringUntil(',').toInt(); | ||||||
|  |           streamSkipUntil('\n');  // Skip the reason code | ||||||
|  |           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||||
|  |             sockets[mux]->sock_connected = false; | ||||||
|  |           } | ||||||
|  |           data = ""; | ||||||
|  |           DBG("### Closed: ", mux); | ||||||
|  |         } else if (data.endsWith(GF("+CIPEVENT:"))) { | ||||||
|  |           // Need to close all open sockets and release the network library. | ||||||
|  |           // User will then need to reconnect. | ||||||
|  |           DBG("### Network error!"); | ||||||
|  |           if (!isGprsConnected()) { | ||||||
|  |             gprsDisconnect(); | ||||||
|  |           } | ||||||
|  |           data = ""; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } while (millis() - startMillis < timeout_ms); | ||||||
|  | finish: | ||||||
|  |     if (!index) { | ||||||
|  |       data.trim(); | ||||||
|  |       if (data.length()) { | ||||||
|  |         DBG("### Unhandled:", data); | ||||||
|  |       } | ||||||
|  |       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) | ||||||
|  |   { | ||||||
|  |     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) | ||||||
|  |   { | ||||||
|  |     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | public: | ||||||
|  |   Stream&       stream; | ||||||
|  |  | ||||||
|  | protected: | ||||||
|  |   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #endif | ||||||
		Reference in New Issue
	
	Block a user