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:
		
							
								
								
									
										110
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								.clang-format
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | ||||
| --- | ||||
| Language: Cpp | ||||
| # BasedOnStyle:  Google | ||||
| AccessModifierOffset: -1 | ||||
| AlignAfterOpenBracket: Align | ||||
| AlignConsecutiveMacros: false | ||||
| AlignConsecutiveAssignments: true | ||||
| AlignConsecutiveDeclarations: true | ||||
| AlignEscapedNewlines: Left | ||||
| AlignOperands: false | ||||
| AlignTrailingComments: true | ||||
| AllowAllArgumentsOnNextLine: true | ||||
| AllowAllConstructorInitializersOnNextLine: false | ||||
| AllowAllParametersOfDeclarationOnNextLine: false | ||||
| AllowShortBlocksOnASingleLine: true | ||||
| AllowShortCaseLabelsOnASingleLine: true | ||||
| AllowShortFunctionsOnASingleLine: Empty | ||||
| AllowShortLambdasOnASingleLine: All | ||||
| AllowShortIfStatementsOnASingleLine: WithoutElse | ||||
| AllowShortLoopsOnASingleLine: true | ||||
| AlwaysBreakAfterDefinitionReturnType: None | ||||
| AlwaysBreakAfterReturnType: None | ||||
| AlwaysBreakBeforeMultilineStrings: false | ||||
| AlwaysBreakTemplateDeclarations: Yes | ||||
| BinPackArguments: true | ||||
| BinPackParameters: true | ||||
| BreakBeforeBinaryOperators: None | ||||
| BreakBeforeBraces: Attach | ||||
| BreakBeforeInheritanceComma: false | ||||
| BreakInheritanceList: BeforeColon | ||||
| BreakBeforeTernaryOperators: true | ||||
| BreakConstructorInitializersBeforeComma: false | ||||
| BreakConstructorInitializers: BeforeColon | ||||
| BreakAfterJavaFieldAnnotations: false | ||||
| BreakStringLiterals: true | ||||
| ColumnLimit: 80 | ||||
| CommentPragmas: "^ IWYU pragma:" | ||||
| CompactNamespaces: false | ||||
| ConstructorInitializerAllOnOneLineOrOnePerLine: true | ||||
| ConstructorInitializerIndentWidth: 4 | ||||
| ContinuationIndentWidth: 4 | ||||
| Cpp11BracedListStyle: true | ||||
| DerivePointerAlignment: false | ||||
| DisableFormat: false | ||||
| ExperimentalAutoDetectBinPacking: false | ||||
| FixNamespaceComments: true | ||||
| ForEachMacros: | ||||
|   - foreach | ||||
|   - Q_FOREACH | ||||
|   - BOOST_FOREACH | ||||
| IncludeBlocks: Preserve | ||||
| IncludeCategories: | ||||
|   - Regex:           '^<ext/.*\.h>' | ||||
|     Priority:        2 | ||||
|   - Regex:           '^<.*\.h>' | ||||
|     Priority:        1 | ||||
|   - Regex:           '^<.*' | ||||
|     Priority:        2 | ||||
|   - Regex:           '.*' | ||||
|     Priority:        3 | ||||
| IncludeIsMainRegex: '([-_](test|unittest))?$' | ||||
| IndentCaseLabels: true | ||||
| IndentPPDirectives: None | ||||
| IndentWidth: 2 | ||||
| IndentWrappedFunctionNames: false | ||||
| JavaScriptQuotes: Leave | ||||
| JavaScriptWrapImports: true | ||||
| KeepEmptyLinesAtTheStartOfBlocks: false | ||||
| MacroBlockBegin: "" | ||||
| MacroBlockEnd: "" | ||||
| MaxEmptyLinesToKeep: 2 | ||||
| NamespaceIndentation: None | ||||
| # ObjCBinPackProtocolList: Auto | ||||
| ObjCBlockIndentWidth: 2 | ||||
| ObjCSpaceAfterProperty: false | ||||
| ObjCSpaceBeforeProtocolList: true | ||||
| PenaltyBreakAssignment: 2 | ||||
| PenaltyBreakBeforeFirstCallParameter: 19 | ||||
| PenaltyBreakComment: 300 | ||||
| PenaltyBreakFirstLessLess: 120 | ||||
| PenaltyBreakString: 1000 | ||||
| PenaltyBreakTemplateDeclaration: 10 | ||||
| PenaltyExcessCharacter: 60 | ||||
| PenaltyReturnTypeOnItsOwnLine: 5 | ||||
| PointerAlignment: Left | ||||
| PointerBindsToType: true | ||||
| ReflowComments: true | ||||
| SortIncludes: false | ||||
| SortUsingDeclarations: true | ||||
| SpaceAfterCStyleCast: false | ||||
| SpaceAfterLogicalNot: false | ||||
| SpaceAfterTemplateKeyword: true | ||||
| SpaceBeforeAssignmentOperators: true | ||||
| SpaceBeforeCpp11BracedList: false | ||||
| SpaceBeforeCtorInitializerColon: true | ||||
| SpaceBeforeInheritanceColon: true | ||||
| SpaceBeforeParens: ControlStatements | ||||
| SpaceBeforeRangeBasedForLoopColon: true | ||||
| SpaceInEmptyParentheses: false | ||||
| SpacesBeforeTrailingComments: 2 | ||||
| SpacesInAngles: false | ||||
| SpacesInCStyleCastParentheses: false | ||||
| SpacesInContainerLiterals: true | ||||
| SpacesInCStyleCastParentheses: false | ||||
| SpacesInParentheses: false | ||||
| SpacesInSquareBrackets: false | ||||
| Standard: Cpp11 | ||||
| TabWidth: 2 | ||||
| UseTab: Never | ||||
| --- | ||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -20,6 +20,7 @@ | ||||
| .clang_complete | ||||
| .gcc-flags.json | ||||
| platformio.ini | ||||
| extra_envs.ini | ||||
| lib/readme.txt | ||||
| include/readme.txt | ||||
| .atomrc.cson | ||||
|   | ||||
							
								
								
									
										3
									
								
								cpplint.cfg
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								cpplint.cfg
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| # Allow references to be used to change values | ||||
| filter=-runtime/references | ||||
| filter=-build/namespaces | ||||
| @@ -42,7 +42,7 @@ | ||||
| //SoftwareSerial SerialAT(2, 3); // RX, TX | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| @@ -68,8 +68,8 @@ | ||||
| #define GSM_PIN "" | ||||
|  | ||||
| // Set phone numbers, if you want to test SMS and Calls | ||||
| //#define SMS_TARGET  "+380xxxxxxxxx" | ||||
| //#define CALL_TARGET "+380xxxxxxxxx" | ||||
| // #define SMS_TARGET  "+380xxxxxxxxx" | ||||
| // #define CALL_TARGET "+380xxxxxxxxx" | ||||
|  | ||||
| // Your GPRS credentials, if any | ||||
| const char apn[]  = "YourAPN"; | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
|  | ||||
| // Default heartbeat interval for GSM is 60 | ||||
| // If you want override this value, uncomment and set this option: | ||||
| //#define BLYNK_HEARTBEAT 30 | ||||
| // #define BLYNK_HEARTBEAT 30 | ||||
|  | ||||
| // Select your modem: | ||||
| #define TINY_GSM_MODEM_SIM800 | ||||
|   | ||||
| @@ -52,14 +52,14 @@ | ||||
| #define TINY_GSM_RX_BUFFER 1024 | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| //#define LOGGING  // <- Logging is for the HTTP library | ||||
| // #define LOGGING  // <- Logging is for the HTTP library | ||||
|  | ||||
| // Add a reception delay - may be needed for a fast processor at a slow baud rate | ||||
| //#define TINY_GSM_YIELD() { delay(2); } | ||||
| // #define TINY_GSM_YIELD() { delay(2); } | ||||
|  | ||||
| // Define how you're planning to connect to the internet | ||||
| #define TINY_GSM_USE_GPRS true | ||||
| @@ -217,7 +217,7 @@ void loop() { | ||||
|   client.print("Connection: close\r\n\r\n"); | ||||
|  | ||||
|   // Let's see what the entire elapsed time is, from after we send the request. | ||||
|   unsigned long timeElapsed = millis(); | ||||
|   uint32_t timeElapsed = millis(); | ||||
|  | ||||
|   SerialMon.println(F("Waiting for response header")); | ||||
|  | ||||
| @@ -246,7 +246,7 @@ void loop() { | ||||
|         // SerialMon.print(c, HEX); | ||||
|         // SerialMon.print(' '); | ||||
|         // if (isprint(c)) | ||||
|         //   SerialMon.print((char) c); | ||||
|         //   SerialMon.print(reinterpret_cast<char> c); | ||||
|         // else | ||||
|         //   SerialMon.print('*'); | ||||
|         // SerialMon.print(' '); | ||||
| @@ -301,7 +301,7 @@ void loop() { | ||||
|     while (readLength < contentLength && client.connected() && millis() - clientReadStartTime < clientReadTimeout) { | ||||
|       while (client.available()) { | ||||
|         uint8_t c = client.read(); | ||||
|         //SerialMon.print((char)c);       // Uncomment this to show data | ||||
|         //SerialMon.print(reinterpret_cast<char>c);  // Uncomment this to show data | ||||
|         crc.update(c); | ||||
|         readLength++; | ||||
|         if (readLength % (contentLength / 13) == 0) { | ||||
|   | ||||
| @@ -57,18 +57,18 @@ | ||||
| #define TINY_GSM_RX_BUFFER 650 | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| //#define LOGGING  // <- Logging is for the HTTP library | ||||
| // #define LOGGING  // <- Logging is for the HTTP library | ||||
|  | ||||
| // Range to attempt to autobaud | ||||
| #define GSM_AUTOBAUD_MIN 9600 | ||||
| #define GSM_AUTOBAUD_MAX 115200 | ||||
|  | ||||
| // Add a reception delay - may be needed for a fast processor at a slow baud rate | ||||
| //#define TINY_GSM_YIELD() { delay(2); } | ||||
| // #define TINY_GSM_YIELD() { delay(2); } | ||||
|  | ||||
| // Define how you're planning to connect to the internet | ||||
| #define TINY_GSM_USE_GPRS true | ||||
|   | ||||
| @@ -49,18 +49,18 @@ | ||||
| #define TINY_GSM_RX_BUFFER 650 | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| //#define LOGGING  // <- Logging is for the HTTP library | ||||
| // #define LOGGING  // <- Logging is for the HTTP library | ||||
|  | ||||
| // Range to attempt to autobaud | ||||
| #define GSM_AUTOBAUD_MIN 9600 | ||||
| #define GSM_AUTOBAUD_MAX 115200 | ||||
|  | ||||
| // Add a reception delay - may be needed for a fast processor at a slow baud rate | ||||
| //#define TINY_GSM_YIELD() { delay(2); } | ||||
| // #define TINY_GSM_YIELD() { delay(2); } | ||||
|  | ||||
| // Define how you're planning to connect to the internet | ||||
| #define TINY_GSM_USE_GPRS true | ||||
|   | ||||
| @@ -60,7 +60,7 @@ | ||||
| //SoftwareSerial SerialAT(2, 3); // RX, TX | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| @@ -70,7 +70,7 @@ | ||||
| #define GSM_AUTOBAUD_MAX 115200 | ||||
|  | ||||
| // Add a reception delay - may be needed for a fast processor at a slow baud rate | ||||
| //#define TINY_GSM_YIELD() { delay(2); } | ||||
| // #define TINY_GSM_YIELD() { delay(2); } | ||||
|  | ||||
| // Define how you're planning to connect to the internet | ||||
| #define TINY_GSM_USE_GPRS true | ||||
| @@ -125,7 +125,7 @@ PubSubClient mqtt(client); | ||||
| #define LED_PIN 13 | ||||
| int ledStatus = LOW; | ||||
|  | ||||
| long lastReconnectAttempt = 0; | ||||
| uint32_t lastReconnectAttempt = 0; | ||||
|  | ||||
| void mqttCallback(char* topic, byte* payload, unsigned int len) { | ||||
|   SerialMon.print("Message arrived ["); | ||||
| @@ -252,7 +252,7 @@ void loop() { | ||||
|   if (!mqtt.connected()) { | ||||
|     SerialMon.println("=== MQTT NOT CONNECTED ==="); | ||||
|     // Reconnect every 10 seconds | ||||
|     unsigned long t = millis(); | ||||
|     uint32_t t = millis(); | ||||
|     if (t - lastReconnectAttempt > 10000L) { | ||||
|       lastReconnectAttempt = t; | ||||
|       if (mqttConnect()) { | ||||
|   | ||||
| @@ -47,7 +47,7 @@ | ||||
| #define TINY_GSM_RX_BUFFER 650 | ||||
|  | ||||
| // See all AT commands, if wanted | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Define the serial console for debug prints, if needed | ||||
| #define TINY_GSM_DEBUG SerialMon | ||||
| @@ -57,10 +57,10 @@ | ||||
| #define GSM_AUTOBAUD_MAX 115200 | ||||
|  | ||||
| // Add a reception delay - may be needed for a fast processor at a slow baud rate | ||||
| //#define TINY_GSM_YIELD() { delay(2); } | ||||
| // #define TINY_GSM_YIELD() { delay(2); } | ||||
|  | ||||
| // Uncomment this if you want to use SSL | ||||
| //#define USE_SSL | ||||
| // #define USE_SSL | ||||
|  | ||||
| // Define how you're planning to connect to the internet | ||||
| #define TINY_GSM_USE_GPRS true | ||||
| @@ -210,7 +210,7 @@ void loop() { | ||||
|   client.print("Connection: close\r\n\r\n"); | ||||
|   client.println(); | ||||
|  | ||||
|   unsigned long timeout = millis(); | ||||
|   uint32_t timeout = millis(); | ||||
|   while (client.connected() && millis() - timeout < 10000L) { | ||||
|     // Print available data | ||||
|     while (client.available()) { | ||||
|   | ||||
| @@ -12,15 +12,15 @@ | ||||
| #define TINY_GSM_MODEM_UBLOX | ||||
|  | ||||
| // Increase RX buffer if needed | ||||
| //#define TINY_GSM_RX_BUFFER 512 | ||||
| // #define TINY_GSM_RX_BUFFER 512 | ||||
|  | ||||
| #include <TinyGsmClient.h> | ||||
|  | ||||
| // Uncomment this if you want to see all AT commands | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Uncomment this if you want to use SSL | ||||
| //#define USE_SSL | ||||
| // #define USE_SSL | ||||
|  | ||||
| // Set serial for debug console (to the Serial Monitor, speed 115200) | ||||
| #define SerialMon Serial | ||||
| @@ -108,7 +108,7 @@ void loop() { | ||||
|   client.print(String("Host: ") + server + "\r\n"); | ||||
|   client.print("Connection: close\r\n\r\n"); | ||||
|  | ||||
|   unsigned long timeout = millis(); | ||||
|   uint32_t timeout = millis(); | ||||
|   while (client.connected() && millis() - timeout < 10000L) { | ||||
|     // Print available data | ||||
|     while (client.available()) { | ||||
|   | ||||
| @@ -18,16 +18,16 @@ | ||||
| #define TINY_GSM_MODEM_SIM800 | ||||
|  | ||||
| // Increase RX buffer if needed | ||||
| //#define TINY_GSM_RX_BUFFER 512 | ||||
| // #define TINY_GSM_RX_BUFFER 512 | ||||
|  | ||||
| #include <TinyGsmClient.h> | ||||
| #include <ArduinoHttpClient.h> | ||||
|  | ||||
| // Uncomment this if you want to see all AT commands | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
| // Uncomment this if you want to use SSL | ||||
| //#define USE_SSL | ||||
| // #define USE_SSL | ||||
|  | ||||
| // Set serial for debug console (to the Serial Monitor, speed 115200) | ||||
| #define SerialMon SerialUSB | ||||
|   | ||||
| @@ -28,7 +28,7 @@ | ||||
| #define SerialAT Serial1 | ||||
|  | ||||
| // Uncomment this if you want to see all AT commands | ||||
| //#define DUMP_AT_COMMANDS | ||||
| // #define DUMP_AT_COMMANDS | ||||
|  | ||||
|  | ||||
| #ifdef DUMP_AT_COMMANDS | ||||
|   | ||||
| @@ -6,129 +6,128 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClient_h | ||||
| #define TinyGsmClient_h | ||||
| #ifndef SRC_TINYGSMCLIENT_h | ||||
| #define SRC_TINYGSMCLIENT_h | ||||
|  | ||||
| #if defined(TINY_GSM_MODEM_SIM800) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientSIM800.h> | ||||
|   typedef TinyGsmSim800 TinyGsm; | ||||
|   typedef TinyGsmSim800::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmSim800::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientSIM800.h" | ||||
| typedef TinyGsmSim800                        TinyGsm; | ||||
| typedef TinyGsmSim800::GsmClientSim800       TinyGsmClient; | ||||
| typedef TinyGsmSim800::GsmClientSecureSim800 TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SIM808) || defined(TINY_GSM_MODEM_SIM868) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #define TINY_GSM_MODEM_HAS_GPS | ||||
|   #include <TinyGsmClientSIM808.h> | ||||
|   typedef TinyGsmSim808 TinyGsm; | ||||
|   typedef TinyGsmSim808::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmSim808::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #define TINY_GSM_MODEM_HAS_GPS | ||||
| #include "TinyGsmClientSIM808.h" | ||||
| typedef TinyGsmSim808                        TinyGsm; | ||||
| typedef TinyGsmSim808::GsmClientSim800       TinyGsmClient; | ||||
| typedef TinyGsmSim808::GsmClientSecureSim800 TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SIM900) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientSIM800.h> | ||||
|   typedef TinyGsmSim800 TinyGsm; | ||||
|   typedef TinyGsmSim800::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientSIM800.h" | ||||
| typedef TinyGsmSim800                  TinyGsm; | ||||
| typedef TinyGsmSim800::GsmClientSim800 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SIM7000) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_GPS | ||||
|   #include <TinyGsmClientSIM7000.h> | ||||
|   typedef TinyGsmSim7000 TinyGsm; | ||||
|   typedef TinyGsmSim7000::GsmClient TinyGsmClient; | ||||
|   // typedef TinyGsmSim7000::GsmClientSecure TinyGsmClientSecure; TODO! | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_GPS | ||||
| #include "TinyGsmClientSIM7000.h" | ||||
| typedef TinyGsmSim7000                   TinyGsm; | ||||
| typedef TinyGsmSim7000::GsmClientSim7000 TinyGsmClient; | ||||
| // typedef TinyGsmSim7000::GsmClientSecureSim7000 TinyGsmClientSecure; TODO! | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SIM5320) || defined(TINY_GSM_MODEM_SIM5360) || \ | ||||
|     defined(TINY_GSM_MODEM_SIM5300) || defined(TINY_GSM_MODEM_SIM7100) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientSIM5360.h> | ||||
|   typedef TinyGsmSim5360 TinyGsm; | ||||
|   typedef TinyGsmSim5360::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientSIM5360.h" | ||||
| typedef TinyGsmSim5360                   TinyGsm; | ||||
| typedef TinyGsmSim5360::GsmClientSim5360 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SIM7600) || defined(TINY_GSM_MODEM_SIM7800) || \ | ||||
|     defined(TINY_GSM_MODEM_SIM7500) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientSIM7600.h> | ||||
|   typedef TinyGsmSim7600 TinyGsm; | ||||
|   typedef TinyGsmSim7600::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientSIM7600.h" | ||||
| typedef TinyGsmSim7600                   TinyGsm; | ||||
| typedef TinyGsmSim7600::GsmClientSim7600 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_UBLOX) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientUBLOX.h> | ||||
|   typedef TinyGsmUBLOX TinyGsm; | ||||
|   typedef TinyGsmUBLOX::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmUBLOX::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientUBLOX.h" | ||||
| typedef TinyGsmUBLOX                       TinyGsm; | ||||
| typedef TinyGsmUBLOX::GsmClientUBLOX       TinyGsmClient; | ||||
| typedef TinyGsmUBLOX::GsmClientSecureUBLOX TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SARAR4) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientSaraR4.h> | ||||
|   typedef TinyGsmSaraR4 TinyGsm; | ||||
|   typedef TinyGsmSaraR4::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmSaraR4::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientSaraR4.h" | ||||
| typedef TinyGsmSaraR4                    TinyGsm; | ||||
| typedef TinyGsmSaraR4::GsmClientSaraR4   TinyGsmClient; | ||||
| typedef TinyGsmSaraR4::GsmClientSecureR4 TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_M95) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientM95.h> | ||||
|   typedef TinyGsmM95 TinyGsm; | ||||
|   typedef TinyGsmM95::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientM95.h" | ||||
| typedef TinyGsmM95               TinyGsm; | ||||
| typedef TinyGsmM95::GsmClientM95 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_BG96) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientBG96.h> | ||||
|   typedef TinyGsmBG96 TinyGsm; | ||||
|   typedef TinyGsmBG96::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientBG96.h" | ||||
| typedef TinyGsmBG96                TinyGsm; | ||||
| typedef TinyGsmBG96::GsmClientBG96 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_A6) || defined(TINY_GSM_MODEM_A7) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientA6.h> | ||||
|   typedef TinyGsmA6 TinyGsm; | ||||
|   typedef TinyGsmA6::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientA6.h" | ||||
| typedef TinyGsmA6              TinyGsm; | ||||
| typedef TinyGsmA6::GsmClientA6 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_M590) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #include <TinyGsmClientM590.h> | ||||
|   typedef TinyGsmM590 TinyGsm; | ||||
|   typedef TinyGsmM590::GsmClient TinyGsmClient; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #include "TinyGsmClientM590.h" | ||||
| typedef TinyGsmM590                TinyGsm; | ||||
| typedef TinyGsmM590::GsmClientM590 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_MC60) || defined(TINY_GSM_MODEM_MC60E) | ||||
|   #include <TinyGsmClientMC60.h> | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_GPS | ||||
|   typedef TinyGsmMC60 TinyGsm; | ||||
|   typedef TinyGsmMC60::GsmClient TinyGsmClient; | ||||
| #include "TinyGsmClientMC60.h" | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_GPS | ||||
| typedef TinyGsmMC60                TinyGsm; | ||||
| typedef TinyGsmMC60::GsmClientMC60 TinyGsmClient; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_ESP8266) | ||||
|   #define TINY_GSM_MODEM_HAS_WIFI | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientESP8266.h> | ||||
|   typedef TinyGsmESP8266 TinyGsm; | ||||
|   typedef TinyGsmESP8266::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmESP8266::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_WIFI | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientESP8266.h" | ||||
| typedef TinyGsmESP8266                         TinyGsm; | ||||
| typedef TinyGsmESP8266::GsmClientESP8266       TinyGsmClient; | ||||
| typedef TinyGsmESP8266::GsmClientSecureESP8266 TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_XBEE) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_WIFI | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientXBee.h> | ||||
|   typedef TinyGsmXBee TinyGsm; | ||||
|   typedef TinyGsmXBee::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmXBee::GsmClientSecure TinyGsmClientSecure; | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_WIFI | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientXBee.h" | ||||
| typedef TinyGsmXBee                      TinyGsm; | ||||
| typedef TinyGsmXBee::GsmClientXBee       TinyGsmClient; | ||||
| typedef TinyGsmXBee::GsmClientSecureXBee TinyGsmClientSecure; | ||||
|  | ||||
| #elif defined(TINY_GSM_MODEM_SEQUANS_MONARCH) | ||||
|   #define TINY_GSM_MODEM_HAS_GPRS | ||||
|   #define TINY_GSM_MODEM_HAS_SSL | ||||
|   #include <TinyGsmClientSequansMonarch.h> | ||||
|   typedef TinyGsmSequansMonarch TinyGsm; | ||||
|   typedef TinyGsmSequansMonarch::GsmClient TinyGsmClient; | ||||
|   typedef TinyGsmSequansMonarch::GsmClientSecure TinyGsmClientSecure; | ||||
|  | ||||
| #define TINY_GSM_MODEM_HAS_GPRS | ||||
| #define TINY_GSM_MODEM_HAS_SSL | ||||
| #include "TinyGsmClientSequansMonarch.h" | ||||
| typedef TinyGsmSequansMonarch                                TinyGsm; | ||||
| typedef TinyGsmSequansMonarch::GsmClientSequansMonarch       TinyGsmClient; | ||||
| typedef TinyGsmSequansMonarch::GsmClientSecureSequansMonarch TinyGsmClientSecure; | ||||
|  | ||||
| #else | ||||
|   #error "Please define GSM modem model" | ||||
| #error "Please define GSM modem model" | ||||
| #endif | ||||
|  | ||||
| #endif | ||||
|   | ||||
| @@ -6,31 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientA6_h | ||||
| #define TinyGsmClientA6_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientA6") | ||||
| #ifndef SRC_TINYGSMCLIENTA6_H_ | ||||
| #define SRC_TINYGSMCLIENTA6_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientA6") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 256 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 8 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,27 +31,25 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmA6 | ||||
| { | ||||
|     : public TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmA6, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientA6 : public GsmClient { | ||||
|     friend class TinyGsmA6; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientA6() {} | ||||
|  | ||||
|   GsmClient(TinyGsmA6& modem) { | ||||
|     init(&modem); | ||||
|     explicit GsmClientA6(TinyGsmA6& modem) { | ||||
|       init(&modem, -1); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|   bool init(TinyGsmA6* modem) { | ||||
|     bool init(TinyGsmA6* modem, uint8_t) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = -1; | ||||
|       sock_connected = false; | ||||
| @@ -67,8 +57,8 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -80,71 +70,62 @@ public: | ||||
|       } | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       TINY_GSM_YIELD(); | ||||
|       at->sendAT(GF("+CIPCLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(maxWaitMs); | ||||
|       rx.clear(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(1000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(1000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmA6*      at; | ||||
|   uint8_t         mux; | ||||
|   bool            sock_connected; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|   // Doesn't support SSL | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmA6(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmA6(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|    bool begin(const char* pin = NULL) { | ||||
|      return init(pin); | ||||
|    } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     // sendAT(GF("&FZ"));  // Factory + Reset | ||||
|     // waitResponse(); | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| @@ -152,7 +133,8 @@ public: | ||||
|     sendAT(GF("+CMEE=0"));  // turn off error codes | ||||
| #endif | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMER=3,0,0,2"));  // Set unsolicited result code output destination | ||||
|     sendAT( | ||||
|         GF("+CMER=3,0,0,2"));  // Set unsolicited result code output destination | ||||
|     waitResponse(); | ||||
|  | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
| @@ -162,151 +144,90 @@ public: | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|     #if defined(TINY_GSM_MODEM_A6) | ||||
|       return "AI-Thinker A6"; | ||||
|     #elif defined(TINY_GSM_MODEM_A7) | ||||
|       return "AI-Thinker A7"; | ||||
|     #endif | ||||
|     return "AI-Thinker A6"; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|   bool factoryDefaultImpl() { | ||||
|     sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write | ||||
|     waitResponse(); | ||||
|     sendAT(GF("&W"));  // Write configuration | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+RST=1")); | ||||
|     delay(3000); | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPOF")); | ||||
|     // +CPOF: MS OFF OK | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
|   String getSimCCID() { | ||||
|  protected: | ||||
|   String getSimCCIDImpl() { | ||||
|     sendAT(GF("+CCID")); | ||||
|     if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+SCID: SIM Card ID:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) | ||||
|  | ||||
|   String getOperator() { | ||||
|     sendAT(GF("+COPS=3,0")); // Set format | ||||
|     waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+COPS?")); | ||||
|     if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     streamSkipUntil('"'); // Skip mode and format | ||||
|     String res = stream.readStringUntil('"'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     sendAT(GF("+CGATT=1")); | ||||
|     if (waitResponse(60000L) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     // TODO: wait AT+CGATT? | ||||
|     // TODO(?): wait AT+CGATT? | ||||
|  | ||||
|     sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); | ||||
|     waitResponse(); | ||||
| @@ -314,120 +235,93 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     if (!user) user = ""; | ||||
|     if (!pwd) pwd = ""; | ||||
|     sendAT(GF("+CSTT=\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); | ||||
|     if (waitResponse(60000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     sendAT(GF("+CGACT=1,1")); | ||||
|     waitResponse(60000L); | ||||
|  | ||||
|     sendAT(GF("+CIPMUX=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|   bool gprsDisconnectImpl() { | ||||
|     // Shut the TCP/IP connection | ||||
|     sendAT(GF("+CIPSHUT")); | ||||
|     if (waitResponse(60000L) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     for (int i = 0; i<3; i++) { | ||||
|     for (int i = 0; i < 3; i++) { | ||||
|       sendAT(GF("+CGATT=0")); | ||||
|       if (waitResponse(5000L) == 1) | ||||
|         return true; | ||||
|       if (waitResponse(5000L) == 1) { return true; } | ||||
|     } | ||||
|  | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool isGprsConnected() { | ||||
|     sendAT(GF("+CGATT?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     int res = stream.readStringUntil('\n').toInt(); | ||||
|   String getOperatorImpl() { | ||||
|     sendAT(GF("+COPS=3,0"));  // Set format | ||||
|     waitResponse(); | ||||
|     return (res == 1); | ||||
|  | ||||
|     sendAT(GF("+COPS?")); | ||||
|     if (waitResponse(GF(GSM_NL "+COPS:")) != 1) { return ""; } | ||||
|     streamSkipUntil('"');  // Skip mode and format | ||||
|     String res = stream.readStringUntil('"'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+CIFSR")); | ||||
|     String res; | ||||
|     if (waitResponse(10000L, res) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, res) != 1) { return ""; } | ||||
|     res.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res.replace(GSM_NL, ""); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() { | ||||
|     sendAT(GF("A")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   // Returns true on pick-up, false on error/busy | ||||
|   bool callNumber(const String& number) { | ||||
|   bool callNumberImpl(const String& number) { | ||||
|     if (number == GF("last")) { | ||||
|       sendAT(GF("DLST")); | ||||
|     } else { | ||||
|       sendAT(GF("D\""), number, "\";"); | ||||
|     } | ||||
|  | ||||
|     if (waitResponse(5000L) != 1) { | ||||
|     if (waitResponse(5000L) != 1) { return false; } | ||||
|  | ||||
|     if (waitResponse(60000L, GF(GSM_NL "+CIEV: \"CALL\",1"), | ||||
|                      GF(GSM_NL "+CIEV: \"CALL\",0"), GFP(GSM_ERROR)) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     if (waitResponse(60000L, | ||||
|         GF(GSM_NL "+CIEV: \"CALL\",1"), | ||||
|         GF(GSM_NL "+CIEV: \"CALL\",0"), | ||||
|         GFP(GSM_ERROR)) != 1) | ||||
|     { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     int rsp = waitResponse(60000L, | ||||
|               GF(GSM_NL "+CIEV: \"SOUNDER\",0"), | ||||
|     int rsp = waitResponse(60000L, GF(GSM_NL "+CIEV: \"SOUNDER\",0"), | ||||
|                            GF(GSM_NL "+CIEV: \"CALL\",0")); | ||||
|  | ||||
|     int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), GF(GSM_NL "NO ANSWER" GSM_NL)); | ||||
|     int rsp2 = waitResponse(300L, GF(GSM_NL "BUSY" GSM_NL), | ||||
|                             GF(GSM_NL "NO ANSWER" GSM_NL)); | ||||
|  | ||||
|     return rsp == 1 && rsp2 == 0; | ||||
|   } | ||||
|  | ||||
|   bool callHangup() { | ||||
|     sendAT(GF("H")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   // 0-9,*,#,A,B,C,D | ||||
|   bool dtmfSend(char cmd, unsigned duration_ms = 100) { | ||||
|   bool dtmfSendImpl(char cmd, unsigned duration_ms = 100) { | ||||
|     duration_ms = constrain(duration_ms, 100, 1000); | ||||
|  | ||||
|     // The duration parameter is not working, so we simulate it using delay.. | ||||
|     // TODO: Maybe there's another way... | ||||
|     // TODO(?): Maybe there's another way... | ||||
|  | ||||
|     //sendAT(GF("+VTD="), duration_ms / 100); | ||||
|     //waitResponse(); | ||||
|     // sendAT(GF("+VTD="), duration_ms / 100); | ||||
|     // waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+VTS="), cmd); | ||||
|     if (waitResponse(10000L) == 1) { | ||||
| @@ -440,7 +334,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * Audio functions | ||||
|    */ | ||||
|  | ||||
|  public: | ||||
|   bool audioSetHeadphones() { | ||||
|     sendAT(GF("+SNFS=0")); | ||||
|     return waitResponse() == 1; | ||||
| @@ -459,19 +353,15 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|  protected: | ||||
|   String sendUSSDImpl(const String& code) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\",15")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return ""; } | ||||
|     if (waitResponse(GF(GSM_NL "+CUSD:")) != 1) { return ""; } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
| @@ -486,37 +376,34 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|   // Note - the clock probably has to be set manaually first | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|   int8_t getBattPercentImpl() { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } | ||||
|     streamSkipUntil(',');  // Skip battery charge status | ||||
|     // Read battery charge level | ||||
|     int res = stream.readStringUntil('\n').toInt(); | ||||
| @@ -525,23 +412,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() { | ||||
|   bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                         uint16_t& milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Read battery charge status | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } | ||||
|     chargeState = stream.readStringUntil(',').toInt(); | ||||
|     percent     = stream.readStringUntil('\n').toInt(); | ||||
|     milliVolts  = 0; | ||||
| @@ -550,32 +424,25 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t* mux, int timeout_s = 75) { | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t* mux, | ||||
|                     int timeout_s = 75) { | ||||
|     uint32_t startMillis = millis(); | ||||
|     uint32_t timeout_ms  = ((uint32_t)timeout_s) * 1000; | ||||
|  | ||||
|     sendAT(GF("+CIPSTART="), GF("\"TCP"), GF("\",\""), host, GF("\","), port); | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+CIPNUM:")) != 1) { return false; } | ||||
|     int newMux = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     int rsp = waitResponse((timeout_ms- (millis() - startMillis)), | ||||
|                            GF("CONNECT OK" GSM_NL), | ||||
|                            GF("CONNECT FAIL" GSM_NL), | ||||
|     int rsp = waitResponse((timeout_ms - (millis() - startMillis)), | ||||
|                            GF("CONNECT OK" GSM_NL), GF("CONNECT FAIL" GSM_NL), | ||||
|                            GF("ALREADY CONNECT" GSM_NL)); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     *mux = newMux; | ||||
|  | ||||
|     return (1 == rsp); | ||||
| @@ -583,37 +450,38 @@ protected: | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(2000L, GF(GSM_NL ">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(10000L, GFP(GSM_OK), GF(GSM_NL "FAIL")) != 1) { return 0; } | ||||
|     return len; | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t, uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|   size_t modemGetAvailable(uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t) { | ||||
|     sendAT(GF("+CIPSTATUS")); //TODO mux? | ||||
|     int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); | ||||
|     sendAT(GF("+CIPSTATUS"));  // TODO(?) mux? | ||||
|     int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), | ||||
|                            GF(",\"CLOSING\""), GF(",\"INITIAL\"")); | ||||
|     waitResponse(); | ||||
|     return 1 == res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -622,14 +490,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -654,11 +522,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           } else { | ||||
|             DBG("### Got: ", len, "->", sockets[mux]->rx.free()); | ||||
|           } | ||||
|           while (len--) { | ||||
|             TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|           } | ||||
|           if (len_orig > sockets[mux]->available()) { // TODO | ||||
|             DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); | ||||
|           while (len--) { moveCharFromStreamToFifo(mux); } | ||||
|           // TODO(?) Deal with missing characters | ||||
|           if (len_orig > sockets[mux]->available()) { | ||||
|             DBG("### Fewer characters received than expected: ", | ||||
|                 sockets[mux]->available(), " vs ", len_orig); | ||||
|           } | ||||
|           data = ""; | ||||
|         } else if (data.endsWith(GF("+TCPCLOSED:"))) { | ||||
| @@ -671,38 +539,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&      stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientA6* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*  gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTA6_H_ | ||||
|   | ||||
| @@ -6,31 +6,23 @@ | ||||
|  * @date       Apr 2018 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientBG96_h | ||||
| #define TinyGsmClientBG96_h | ||||
| //#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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,26 +31,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| class TinyGsmBG96 | ||||
|     : public TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmBG96, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmBG96: public TinyGsmUTFSMS<TinyGsmBG96> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientBG96 : public GsmClient { | ||||
|     friend class TinyGsmBG96; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientBG96() {} | ||||
|  | ||||
|   GsmClient(TinyGsmBG96& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientBG96(TinyGsmBG96& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmBG96* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -72,441 +62,272 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    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); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+QICLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmBG96*    at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|  | ||||
| // class GsmClientSecure : public GsmClient | ||||
| // { | ||||
| // public: | ||||
| //   GsmClientSecure() {} | ||||
| // | ||||
| //   GsmClientSecure(TinyGsmBG96& modem, uint8_t mux = 1) | ||||
| //     : GsmClient(modem, mux) | ||||
| //   {} | ||||
| // | ||||
| //   virtual ~GsmClientSecure(){} | ||||
| // | ||||
| // public: | ||||
| //   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
| //     stop(); | ||||
| //     TINY_GSM_YIELD(); | ||||
| //     rx.clear(); | ||||
| //     sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
| //     return sock_connected; | ||||
| //   } | ||||
| // }; | ||||
|  | ||||
|  | ||||
| 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: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 20) { | ||||
|    if (ssl) { | ||||
|      DBG("SSL not yet supported on this module!"); | ||||
|    } | ||||
|     if (ssl) { DBG("SSL not yet supported on this module!"); } | ||||
|     int      rsp; | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|  | ||||
|     // <PDPcontextID>(1-16), <connectID>(0-11),"TCP/UDP/TCP LISTENER/UDP SERVICE", | ||||
|     // "<IP_address>/<domain_name>",<remote_port>,<local_port>,<access_mode>(0-2 0=buffer) | ||||
|     sendAT(GF("+QIOPEN=1,"), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port, GF(",0,0")); | ||||
|     rsp = waitResponse(); | ||||
|     // <PDPcontextID>(1-16), <connectID>(0-11), | ||||
|     // "TCP/UDP/TCP LISTENER/UDPSERVICE", "<IP_address>/<domain_name>", | ||||
|     // <remote_port>,<local_port>,<access_mode>(0-2; 0=buffer) | ||||
|     sendAT(GF("+QIOPEN=1,"), mux, GF(",\""), GF("TCP"), GF("\",\""), host, | ||||
|            GF("\","), port, GF(",0,0")); | ||||
|     waitResponse(); | ||||
|  | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+QIOPEN:")) != 1) { return false; } | ||||
|  | ||||
|     if (stream.readStringUntil(',').toInt() != mux) { | ||||
|       return false; | ||||
|     } | ||||
|     if (stream.readStringUntil(',').toInt() != mux) { return false; } | ||||
|     // Read status | ||||
|     rsp = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
| @@ -515,28 +336,20 @@ protected: | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     // TODO: Wait for ACK? AT+QISEND=id,0 | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } | ||||
|     // TODO(?): Wait for ACK? AT+QISEND=id,0 | ||||
|     return len; | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     sendAT(GF("+QIRD="), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+QIRD:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+QIRD:")) != 1) { return 0; } | ||||
|     int len = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     for (int i=0; i<len; i++) { | ||||
|       TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|     } | ||||
|     for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } | ||||
|     waitResponse(); | ||||
|     DBG("### READ:", len, "from", mux); | ||||
|     sockets[mux]->sock_available = modemGetAvailable(mux); | ||||
| @@ -550,23 +363,18 @@ protected: | ||||
|       streamSkipUntil(',');  // Skip total received | ||||
|       streamSkipUntil(',');  // Skip have read | ||||
|       result = stream.readStringUntil('\n').toInt(); | ||||
|       if (result) { | ||||
|         DBG("### DATA AVAILABLE:", result, "on", mux); | ||||
|       } | ||||
|       if (result) { DBG("### DATA AVAILABLE:", result, "on", mux); } | ||||
|       waitResponse(); | ||||
|     } | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   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 | ||||
| @@ -581,19 +389,16 @@ protected: | ||||
|     return 2 == res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -602,14 +407,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -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: | ||||
|  protected: | ||||
|   Stream&        stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientBG96* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*    gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTBG96_H_ | ||||
|   | ||||
| @@ -6,23 +6,20 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientESP8266_h | ||||
| #define TinyGsmClientESP8266_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientESP8266") | ||||
| #ifndef SRC_TINYGSMCLIENTESP8266_H_ | ||||
| #define SRC_TINYGSMCLIENTESP8266_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientESP8266") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 512 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 5 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
| static unsigned   TINY_GSM_TCP_KEEP_ALIVE          = 120; | ||||
|  | ||||
| // <stat> status of ESP8266 station interface | ||||
| @@ -38,26 +35,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN   = 6, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmESP8266 | ||||
| { | ||||
|     : public TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmESP8266, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientESP8266 : public GsmClient { | ||||
|     friend class TinyGsmESP8266; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientESP8266() {} | ||||
|  | ||||
|   GsmClient(TinyGsmESP8266& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmESP8266* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -68,184 +63,159 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       TINY_GSM_YIELD(); | ||||
|       at->sendAT(GF("+CIPCLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(maxWaitMs); | ||||
|       rx.clear(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(5000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(5000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmESP8266* at; | ||||
|   uint8_t         mux; | ||||
|   bool            sock_connected; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSecureESP8266 : public GsmClientESP8266 { | ||||
|    public: | ||||
|     GsmClientSecureESP8266() {} | ||||
|  | ||||
|     explicit GsmClientSecureESP8266(TinyGsmESP8266& modem, uint8_t mux = 1) | ||||
|         : GsmClientESP8266(modem, mux) {} | ||||
|  | ||||
| class GsmClientSecure : public GsmClient | ||||
| { | ||||
| public: | ||||
|   GsmClientSecure() {} | ||||
|  | ||||
|   GsmClientSecure(TinyGsmESP8266& modem, uint8_t mux = 1) | ||||
|     : GsmClient(modem, mux) | ||||
|   {} | ||||
|  | ||||
|   virtual ~GsmClientSecure() {} | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
| }; | ||||
|   }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmESP8266(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmESP8266(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     if (!testAT()) { return false; } | ||||
|     if (pin && strlen(pin) > 0) { | ||||
|       DBG("ESP8266 modules do not use an unlock pin!"); | ||||
|     } | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     sendAT(GF("+CIPMUX=1"));  // Enable Multiple Connections | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     sendAT(GF("+CWMODE_CUR=1"));  // Put into "station" mode | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   String getModemNameImpl() { | ||||
|     return "ESP8266"; | ||||
|   } | ||||
|  | ||||
|   void setBaud(unsigned long baud) { | ||||
|   void setBaudImpl(uint32_t baud) { | ||||
|     sendAT(GF("+UART_CUR="), baud, "8,1,0,0"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|   bool factoryDefaultImpl() { | ||||
|     sendAT(GF("+RESTORE")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   String getModemInfo() { | ||||
|   String getModemInfoImpl() { | ||||
|     sendAT(GF("+GMR")); | ||||
|     String res; | ||||
|     if (waitResponse(1000L, res) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(1000L, res) != 1) { return ""; } | ||||
|     res.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res.replace(GSM_NL, " "); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+RST")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     if (waitResponse(10000L, GF(GSM_NL "ready" GSM_NL)) != 1) { return false; } | ||||
|     delay(500); | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+GSLP=0"));  // Power down indefinitely - until manually reset! | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool radioOffImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  protected: | ||||
|   // SIM card functions don't apply | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     sendAT(GF("+CIPSTATUS")); | ||||
|     if (waitResponse(3000, GF("STATUS:")) != 1) return REG_UNKNOWN; | ||||
| @@ -255,11 +225,8 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|     return (RegStatus)status; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  | ||||
|   int16_t getSignalQuality() { | ||||
|  protected: | ||||
|   int16_t getSignalQualityImpl() { | ||||
|     sendAT(GF("+CWJAP_CUR?")); | ||||
|     int res1 = waitResponse(GF("No AP"), GF("+CWJAP_CUR:")); | ||||
|     if (res1 != 2) { | ||||
| @@ -274,33 +241,28 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|     return res2; | ||||
|   } | ||||
|  | ||||
|   bool isNetworkConnected()  { | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     if (s == REG_OK_IP || s == REG_OK_TCP) { | ||||
|       // with these, we're definitely connected | ||||
|       return true; | ||||
|     } | ||||
|     else if (s == REG_OK_NO_TCP) { | ||||
|     } else if (s == REG_OK_NO_TCP) { | ||||
|       // with this, we may or may not be connected | ||||
|       if (getLocalIP() == "") { | ||||
|         return false; | ||||
|       } | ||||
|       else { | ||||
|       } else { | ||||
|         return true; | ||||
|       } | ||||
|     } | ||||
|     else { | ||||
|     } else { | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * WiFi functions | ||||
|    */ | ||||
|  | ||||
|   bool networkConnect(const char* ssid, const char* pwd) { | ||||
|  protected: | ||||
|   bool networkConnectImpl(const char* ssid, const char* pwd) { | ||||
|     sendAT(GF("+CWJAP_CUR=\""), ssid, GF("\",\""), pwd, GF("\"")); | ||||
|     if (waitResponse(30000L, GFP(GSM_OK), GF(GSM_NL "FAIL" GSM_NL)) != 1) { | ||||
|       return false; | ||||
| @@ -309,7 +271,7 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool networkDisconnect() { | ||||
|   bool networkDisconnectImpl() { | ||||
|     sendAT(GF("+CWQAP")); | ||||
|     bool retVal = waitResponse(10000L) == 1; | ||||
|     waitResponse(GF("WIFI DISCONNECT")); | ||||
| @@ -319,74 +281,107 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|     sendAT(GF("+CIPSTA_CUR??")); | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+CIPSTA_CUR?")); | ||||
|     int res1 = waitResponse(GF("ERROR"), GF("+CWJAP_CUR:")); | ||||
|     if (res1 != 2) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (res1 != 2) { return ""; } | ||||
|     String res2 = stream.readStringUntil('"'); | ||||
|     waitResponse(); | ||||
|     return res2; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  protected: | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  protected: | ||||
|   String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool   sendSMSImpl(const String& number, | ||||
|                      const String& text) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool   sendSMS_UTF16Impl(const char* const number, const void* text, | ||||
|                            size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   String | ||||
|   getGSMDateTimeImpl(TinyGSMDateTimeFormat format) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   // Use: float vBatt = modem.getBattVoltage() / 1000.0; | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t   getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t  getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool     getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                             uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   float    getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 75) | ||||
|  { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; | ||||
|                     bool ssl = false, int timeout_s = 75) { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     if (ssl) { | ||||
|       sendAT(GF("+CIPSSLSIZE=4096")); | ||||
|       waitResponse(); | ||||
|     } | ||||
|     sendAT(GF("+CIPSTART="), mux, ',', ssl ? GF("\"SSL") : GF("\"TCP"), | ||||
|            GF("\",\""), host, GF("\","), port, GF(","), TINY_GSM_TCP_KEEP_ALIVE); | ||||
|     // TODO: Check mux | ||||
|     int rsp = waitResponse(timeout_ms, | ||||
|                            GFP(GSM_OK), | ||||
|                            GFP(GSM_ERROR), | ||||
|            GF("\",\""), host, GF("\","), port, GF(","), | ||||
|            TINY_GSM_TCP_KEEP_ALIVE); | ||||
|     // TODO(?): Check mux | ||||
|     int rsp = waitResponse(timeout_ms, GFP(GSM_OK), GFP(GSM_ERROR), | ||||
|                            GF("ALREADY CONNECT")); | ||||
|     // if (rsp == 3) waitResponse();  // May return "ERROR" after the "ALREADY CONNECT" | ||||
|     // if (rsp == 3) waitResponse(); | ||||
|     // May return "ERROR" after the "ALREADY CONNECT" | ||||
|     return (1 == rsp); | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { | ||||
|     if (waitResponse(10000L, GF(GSM_NL "SEND OK" GSM_NL)) != 1) { return 0; } | ||||
|     return len; | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t, uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|     return len; | ||||
|   size_t modemGetAvailable(uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     sendAT(GF("+CIPSTATUS")); | ||||
|     if (waitResponse(3000, GF("STATUS:")) != 1) return false; | ||||
|     if (waitResponse(3000, GF("STATUS:")) != 1) { return false; } | ||||
|     int status = | ||||
|         waitResponse(GFP(GSM_ERROR), GF("2"), GF("3"), GF("4"), GF("5")); | ||||
|     if (status != 3) { | ||||
| @@ -399,7 +394,8 @@ protected: | ||||
|     } | ||||
|     bool verified_connections[TINY_GSM_MUX_COUNT] = {0, 0, 0, 0, 0}; | ||||
|     for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|       uint8_t has_status = waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); | ||||
|       uint8_t has_status = | ||||
|           waitResponse(GF("+CIPSTATUS:"), GFP(GSM_OK), GFP(GSM_ERROR)); | ||||
|       if (has_status == 1) { | ||||
|         int returned_mux = stream.readStringUntil(',').toInt(); | ||||
|         streamSkipUntil(',');   // Skip mux | ||||
| @@ -418,19 +414,16 @@ protected: | ||||
|     return verified_connections[mux]; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -439,14 +432,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -467,19 +460,21 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           int len      = stream.readStringUntil(':').toInt(); | ||||
|           int len_orig = len; | ||||
|           if (len > sockets[mux]->rx.free()) { | ||||
|             DBG("### Buffer overflow: ", len, "received vs", sockets[mux]->rx.free(), "available"); | ||||
|             DBG("### Buffer overflow: ", len, "received vs", | ||||
|                 sockets[mux]->rx.free(), "available"); | ||||
|           } else { | ||||
|             DBG("### Got Data: ", len, "on", mux); | ||||
|           } | ||||
|           while (len--) { | ||||
|             TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|           } | ||||
|           if (len_orig > sockets[mux]->available()) { // TODO | ||||
|             DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); | ||||
|           while (len--) { moveCharFromStreamToFifo(mux); } | ||||
|           // TODO(SRGDamia1): deal with buffer overflow/missed characters | ||||
|           if (len_orig > sockets[mux]->available()) { | ||||
|             DBG("### Fewer characters received than expected: ", | ||||
|                 sockets[mux]->available(), " vs ", len_orig); | ||||
|           } | ||||
|           data = ""; | ||||
|         } else if (data.endsWith(GF("CLOSED"))) { | ||||
|           int muxStart = max(0,data.lastIndexOf(GSM_NL, data.length()-8)); | ||||
|           int muxStart = | ||||
|               TinyGsmMax(0, data.lastIndexOf(GSM_NL, data.length() - 8)); | ||||
|           int coma = data.indexOf(',', muxStart); | ||||
|           int mux  = data.substring(muxStart, coma).toInt(); | ||||
|           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||
| @@ -490,38 +485,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&           stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientESP8266* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*       gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTESP8266_H_ | ||||
|   | ||||
| @@ -6,31 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientM590_h | ||||
| #define TinyGsmClientM590_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientM590") | ||||
| #ifndef SRC_TINYGSMCLIENTM590_H_ | ||||
| #define SRC_TINYGSMCLIENTM590_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientM590") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 256 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 2 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 3, | ||||
|   REG_DENIED       = 2, | ||||
| @@ -39,26 +31,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmM590 | ||||
| { | ||||
|     : public TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmM590, NO_MODEM_BUFFER, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientM590 : public GsmClient { | ||||
|     friend class TinyGsmM590; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientM590() {} | ||||
|  | ||||
|   GsmClient(TinyGsmM590& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientM590(TinyGsmM590& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmM590* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -69,80 +59,61 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|     sock_connected = at->modemConnect(host, port, mux, timeout_s); | ||||
|  | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       TINY_GSM_YIELD(); | ||||
|       at->sendAT(GF("+TCPCLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(maxWaitMs); | ||||
|       rx.clear(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(1000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_NO_MODEM_FIFO() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(1000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmM590*    at; | ||||
|   uint8_t         mux; | ||||
|   bool            sock_connected; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmM590(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmM590(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     // sendAT(GF("&FZ"));  // Factory + Reset | ||||
|     // waitResponse(); | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| @@ -158,25 +129,20 @@ public: | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   // Doesn't support CGMI | ||||
|   String getModemNameImpl() { | ||||
|     return "Neoway M590"; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|   // Extra stuff here - pwr save, internal stack | ||||
|   bool factoryDefaultImpl() { | ||||
|     sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+ICF=3,1"));  // 8 data 0 parity 1 stop | ||||
| @@ -189,45 +155,37 @@ TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CFUN=15")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     //MODEM:STARTUP | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     // MODEM:STARTUP | ||||
|     waitResponse(60000L, GF(GSM_NL "+PBREADY" GSM_NL)); | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPWROFF")); | ||||
|     return waitResponse(3000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) { | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+ENPWRSAVE="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
| @@ -235,54 +193,29 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_SIMCCID_CCID() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  protected: | ||||
|   // Able to follow all SIM card functions as inherited from the template | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     sendAT(GF("+XISP=0")); | ||||
| @@ -299,37 +232,35 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     sendAT(GF("+XIIC=1")); | ||||
|     waitResponse(); | ||||
|  | ||||
|     const unsigned long timeout_ms = 60000L; | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|     const uint32_t timeout_ms = 60000L; | ||||
|     for (uint32_t start = millis(); millis() - start < timeout_ms;) { | ||||
|       if (isGprsConnected()) { | ||||
|         //goto set_dns; // TODO | ||||
|         // goto set_dns; // TODO | ||||
|         return true; | ||||
|       } | ||||
|       delay(500); | ||||
|     } | ||||
|     return false; | ||||
|  | ||||
| // set_dns:  // TODO | ||||
| //     sendAT(GF("+DNSSERVER=1,8.8.8.8")); | ||||
| //     waitResponse(); | ||||
| // | ||||
| //     sendAT(GF("+DNSSERVER=2,8.8.4.4")); | ||||
| //     waitResponse(); | ||||
|     // set_dns:  // TODO | ||||
|     //     sendAT(GF("+DNSSERVER=1,8.8.8.8")); | ||||
|     //     waitResponse(); | ||||
|     // | ||||
|     //     sendAT(GF("+DNSSERVER=2,8.8.4.4")); | ||||
|     //     waitResponse(); | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|     // TODO: There is no command in AT command set | ||||
|   bool gprsDisconnectImpl() { | ||||
|     // TODO(?): There is no command in AT command set | ||||
|     // XIIC=0 does not work | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool isGprsConnected() { | ||||
|   bool isGprsConnectedImpl() { | ||||
|     sendAT(GF("+XIIC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return false; } | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     waitResponse(); | ||||
|     return res == 1; | ||||
| @@ -338,12 +269,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+XIIC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+XIIC:")) != 1) { return ""; } | ||||
|     stream.readStringUntil(','); | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
| @@ -351,102 +280,63 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  protected: | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("D"), code); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
|     int dcs = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|  | ||||
|     if (dcs == 15) { | ||||
|       return TinyGsmDecodeHex8bit(hex); | ||||
|     } else if (dcs == 72) { | ||||
|       return TinyGsmDecodeHex16bit(hex); | ||||
|     } else { | ||||
|       return hex; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool sendSMS_UTF16(const String& number, const void* text, size_t len) | ||||
|   TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  protected: | ||||
|   bool sendSMS_UTF16Impl(const String& number, const void* text, | ||||
|                          size_t len) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type available | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t   getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t  getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool     getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                             uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   float    getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, int timeout_s = 75) { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; | ||||
|     for (int i=0; i<3; i++) { // TODO: no need for loop? | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, bool, | ||||
|                     int timeout_s = 75) { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     for (int i = 0; i < 3; i++) {  // TODO(?): no need for loop? | ||||
|       String ip = dnsIpQuery(host); | ||||
|  | ||||
|       sendAT(GF("+TCPSETUP="), mux, GF(","), ip, GF(","), port); | ||||
|       int rsp = waitResponse(timeout_ms, | ||||
|                             GF(",OK" GSM_NL), | ||||
|                             GF(",FAIL" GSM_NL), | ||||
|       int rsp = waitResponse(timeout_ms, GF(",OK" GSM_NL), GF(",FAIL" GSM_NL), | ||||
|                              GF("+TCPSETUP:Error" GSM_NL)); | ||||
|       if (1 == rsp) { | ||||
|         return true; | ||||
| @@ -461,50 +351,49 @@ protected: | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+TCPSEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     stream.write((char)0x0D); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.write(static_cast<char>(0x0D)); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+TCPSEND:")) != 1) { return 0; } | ||||
|     stream.readStringUntil('\n'); | ||||
|     return len; | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t, uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|   size_t modemGetAvailable(uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     sendAT(GF("+CIPSTATUS="), mux); | ||||
|     int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), GF(",\"CLOSING\""), GF(",\"INITIAL\"")); | ||||
|     int res = waitResponse(GF(",\"CONNECTED\""), GF(",\"CLOSED\""), | ||||
|                            GF(",\"CLOSING\""), GF(",\"INITIAL\"")); | ||||
|     waitResponse(); | ||||
|     return 1 == res; | ||||
|   } | ||||
|  | ||||
|   String dnsIpQuery(const char* host) { | ||||
|     sendAT(GF("+DNS=\""), host, GF("\"")); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+DNS:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(GF("+DNS:OK" GSM_NL)); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -513,14 +402,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -545,11 +434,11 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           } else { | ||||
|             DBG("### Got: ", len, "->", sockets[mux]->rx.free()); | ||||
|           } | ||||
|           while (len--) { | ||||
|             TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|           } | ||||
|           if (len_orig > sockets[mux]->available()) { // TODO | ||||
|             DBG("### Fewer characters received than expected: ", sockets[mux]->available(), " vs ", len_orig); | ||||
|           while (len--) { moveCharFromStreamToFifo(mux); } | ||||
|           // TODO(?): Handle lost characters | ||||
|           if (len_orig > sockets[mux]->available()) { | ||||
|             DBG("### Fewer characters received than expected: ", | ||||
|                 sockets[mux]->available(), " vs ", len_orig); | ||||
|           } | ||||
|           data = ""; | ||||
|         } else if (data.endsWith(GF("+TCPCLOSE:"))) { | ||||
| @@ -563,38 +452,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&        stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientM590* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*    gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTM590_H_ | ||||
|   | ||||
| @@ -2,35 +2,28 @@ | ||||
|  * @file       TinyGsmClientM95.h | ||||
|  * @author     Volodymyr Shymanskyy, Pacman Pereira, and Replicade Ltd. | ||||
|  * @license    LGPL-3.0 | ||||
|  * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. <http://www.replicade.com> | ||||
|  * @copyright  Copyright (c) 2016 Volodymyr Shymanskyy, (c)2017 Replicade Ltd. | ||||
|  * <http://www.replicade.com> | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientM95_h | ||||
| #define TinyGsmClientM95_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientM95") | ||||
| #ifndef SRC_TINYGSMCLIENTM95_H_ | ||||
| #define SRC_TINYGSMCLIENTM95_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientM95") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 6 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,26 +32,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| class TinyGsmM95 | ||||
|     : public TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmM95, READ_NO_CHECK, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmM95: public TinyGsmUTFSMS<TinyGsmM95> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientM95 : public GsmClient { | ||||
|     friend class TinyGsmM95; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientM95() {} | ||||
|  | ||||
|   GsmClient(TinyGsmM95& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientM95(TinyGsmM95& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmM95* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -70,101 +61,91 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     at->sendAT(GF("+QICLOSE="), mux); | ||||
|     sock_connected = false; | ||||
|     at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR")); | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(75000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       uint32_t startMillis = millis(); | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+QICLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), | ||||
|                        GF("CLOSE OK"), GF("ERROR")); | ||||
|     } | ||||
|     void stop() override { | ||||
|       stop(75000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmM95*     at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   bool            sock_connected; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|  | ||||
| // class GsmClientSecure : public GsmClient | ||||
| // { | ||||
| // public: | ||||
| //   GsmClientSecure() {} | ||||
| // | ||||
| //   GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1) | ||||
| //     : GsmClient(modem, mux) | ||||
| //   {} | ||||
| // | ||||
| //   virtual ~GsmClientSecure() {} | ||||
| // | ||||
| // public: | ||||
| //   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
| //     stop(); | ||||
| //     TINY_GSM_YIELD(); | ||||
| //     rx.clear(); | ||||
| //     sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
| //     return sock_connected; | ||||
| //   } | ||||
| // }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmM95(Stream& stream) | ||||
|     : stream(stream) | ||||
|   /* | ||||
|     class GsmClientSecureM95 : public GsmClientM95 | ||||
|     { | ||||
|     public: | ||||
|       GsmClientSecure() {} | ||||
|  | ||||
|       GsmClientSecure(TinyGsmm95& modem, uint8_t mux = 1) | ||||
|        : GsmClient(modem, mux) | ||||
|       {} | ||||
|  | ||||
|  | ||||
|     public: | ||||
|       virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|         stop(); | ||||
|         TINY_GSM_YIELD(); | ||||
|         rx.clear(); | ||||
|         sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
|         return sock_connected; | ||||
|       } | ||||
|     }; | ||||
|   */ | ||||
|  | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmM95(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     // sendAT(GF("&FZ"));  // Factory + Reset | ||||
|     // waitResponse(); | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| @@ -175,62 +156,43 @@ public: | ||||
|  | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|  | ||||
|     // Enable network time synchronization | ||||
|     sendAT(GF("+QNITZ=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|     return "Quectel M95"; | ||||
|   bool thisHasSSL() { | ||||
|     return false;  // TODO(?): Add SSL support | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|     sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+IPR=0"));   // Auto-baud | ||||
|     waitResponse(); | ||||
|     sendAT(GF("&W"));       // Write configuration | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|     return false;  // TODO: For now | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == 3) { | ||||
|     if (waitResponse(10000L, GF("NORMAL POWER DOWN"), GF("OK"), GF("FAIL")) == | ||||
|         3) { | ||||
|       return false; | ||||
|     } | ||||
|     sendAT(GF("+CFUN=1")); | ||||
| @@ -240,77 +202,51 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+QPOWD=1")); | ||||
|     return waitResponse(300, GF("NORMAL POWER DOWN")) == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|   // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN | ||||
|   // is pulled up, the module can directly enter into sleep mode.If entering | ||||
|   // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled | ||||
|   // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first, | ||||
|   // and then the module can enter into sleep mode. | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+QSCLK="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
|   String getSimCCID() { | ||||
|  protected: | ||||
|   String getSimCCIDImpl() { | ||||
|     sendAT(GF("+QCCID")); | ||||
|     if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+QCCID:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
|   void setHostFormat( bool useDottedQuad ) { | ||||
|     if ( useDottedQuad ) { | ||||
|  public: | ||||
|   void setHostFormat(bool useDottedQuad) { | ||||
|     if (useDottedQuad) { | ||||
|       sendAT(GF("+QIDNSIP=0")); | ||||
|     } else { | ||||
|       sendAT(GF("+QIDNSIP=1")); | ||||
| @@ -318,63 +254,47 @@ TINY_GSM_MODEM_GET_CSQ() | ||||
|     waitResponse(); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     // select foreground context 0 = VIRTUAL_UART_1 | ||||
|     sendAT(GF("+QIFGCNT=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Select GPRS (=1) as the Bearer | ||||
|     sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Select GPRS (=1) as the Bearer | ||||
|     sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, | ||||
|            GF("\"")); | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Select TCP/IP transfer mode - NOT transparent mode | ||||
|     sendAT(GF("+QIMODE=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Enable multiple TCP/IP connections | ||||
|     sendAT(GF("+QIMUX=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Start TCPIP Task and Set APN, User Name and Password | ||||
|     sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" ); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Start TCPIP Task and Set APN, User Name and Password | ||||
|     sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\""); | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Activate GPRS/CSD Context | ||||
|     // Activate GPRS/CSD Context | ||||
|     sendAT(GF("+QIACT")); | ||||
|     if (waitResponse(60000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     // Check that we have a local IP address | ||||
|     if (localIP() == IPAddress(0,0,0,0)) { | ||||
|       return false; | ||||
|     } | ||||
|     if (localIP() == IPAddress(0, 0, 0, 0)) { return false; } | ||||
|  | ||||
|     // Set Method to Handle Received TCP/IP Data | ||||
|     // Mode = 1 - Output a notification when data is received | ||||
|     // “+QIRDI: <id>,<sc>,<sid>” | ||||
|     sendAT(GF("+QINDI=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // // Request an IP header for received data | ||||
|     // // "IPD(data length):" | ||||
| @@ -390,7 +310,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     //   return false; | ||||
|     // } | ||||
|     // | ||||
|     // // Do NOT show the protocol type at the end of the header for received data | ||||
|     // // Do NOT show the protocol type at the end of the header for received | ||||
|     // data | ||||
|     // // IPD(data length)(TCP/UDP): | ||||
|     // sendAT(GF("+QISHOWPT=0")); | ||||
|     // if (waitResponse() != 1) { | ||||
| @@ -407,18 +328,16 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|     sendAT(GF("+QIDEACT")); | ||||
|   bool gprsDisconnectImpl() { | ||||
|     sendAT(GF("+QIDEACT"));  // Deactivate the bearer context | ||||
|     return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+QILOCIP")); | ||||
|     stream.readStringUntil('\n'); | ||||
|     String res = stream.readStringUntil('\n'); | ||||
| @@ -426,142 +345,54 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow all of the phone call functions from the template | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow all template functions | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\"")); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
|     int dcs = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|  | ||||
|     if (dcs == 15) { | ||||
|       return TinyGsmDecodeHex8bit(hex); | ||||
|     } else if (dcs == 72) { | ||||
|       return TinyGsmDecodeHex16bit(hex); | ||||
|     } else { | ||||
|       return hex; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   /** Delete all SMS */ | ||||
|   bool deleteAllSMS() { | ||||
|     sendAT(GF("+QMGDA=6")); | ||||
|     if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) { | ||||
|     if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) { | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   // Use: float vBatt = modem.getBattVoltage() / 1000.0; | ||||
|   uint16_t getBattVoltage() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     streamSkipUntil(','); // Skip battery charge status | ||||
|     streamSkipUntil(','); // Skip battery charge level | ||||
|     // return voltage in mV | ||||
|     uint16_t res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     streamSkipUntil(','); // Skip battery charge status | ||||
|     // Read battery charge level | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Read battery charge status | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     chargeState = stream.readStringUntil(',').toInt(); | ||||
|     percent = stream.readStringUntil(',').toInt(); | ||||
|     milliVolts = stream.readStringUntil('\n').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   float getTemperature() { | ||||
|  protected: | ||||
|   float getTemperatureImpl() { | ||||
|     sendAT(GF("+QTEMP")); | ||||
|     if (waitResponse(GF(GSM_NL "+QTEMP:")) != 1) { | ||||
|       return (float)-9999; | ||||
|       return static_cast<float>(-9999); | ||||
|     } | ||||
|     streamSkipUntil(',');  // Skip mode | ||||
|     // Read charge of thermistor | ||||
| @@ -576,33 +407,25 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 75) { | ||||
|    if (ssl) { | ||||
|      DBG("SSL not yet supported on this module!"); | ||||
|    } | ||||
|     if (ssl) { DBG("SSL not yet supported on this module!"); } | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|    sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); | ||||
|     int rsp = waitResponse(timeout_ms, | ||||
|                            GF("CONNECT OK" GSM_NL), | ||||
|                            GF("CONNECT FAIL" GSM_NL), | ||||
|                            GF("ALREADY CONNECT" GSM_NL)); | ||||
|     sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, | ||||
|            GF("\","), port); | ||||
|     int rsp = | ||||
|         waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), | ||||
|                      GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); | ||||
|     return (1 == rsp); | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } | ||||
|  | ||||
|     // bool allAcknowledged = false; | ||||
|     // // bool failed = false; | ||||
| @@ -621,11 +444,11 @@ protected: | ||||
|     // } | ||||
|     // waitResponse(5000L); | ||||
|  | ||||
|     return len;  // TODO | ||||
|     return len;  // TODO(?): get len/ack properly | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     // TODO:  Does this work???? | ||||
|     // TODO(?):  Does this work???? | ||||
|     // AT+QIRD=<id>,<sc>,<sid>,<len> | ||||
|     // id = GPRS context number = 0, set in GPRS connect | ||||
|     // sc = role in connection = 1, client of connection | ||||
| @@ -641,17 +464,17 @@ protected: | ||||
|       streamSkipUntil(',');  // skip connection type (TCP/UDP) | ||||
|       // read the real length of the retrieved data | ||||
|       uint16_t len = stream.readStringUntil('\n').toInt(); | ||||
|       // We have no way of knowing in advance how much data will be in the buffer | ||||
|       // so when data is received we always assume the buffer is completely full. | ||||
|       // Chances are, this is not true and there's really not that much there. | ||||
|       // In that case, make sure we make sure we re-set the amount of data available. | ||||
|       if (len < size) { | ||||
|           sockets[mux]->sock_available = len; | ||||
|       } | ||||
|       for (uint16_t i=0; i<len; i++) { | ||||
|         TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|       // We have no way of knowing in advance how much data will be in the | ||||
|       // buffer so when data is received we always assume the buffer is | ||||
|       // completely full. Chances are, this is not true and there's really not | ||||
|       // that much there. In that case, make sure we make sure we re-set the | ||||
|       // amount of data available. | ||||
|       if (len < size) { sockets[mux]->sock_available = len; } | ||||
|       for (uint16_t i = 0; i < len; i++) { | ||||
|         moveCharFromStreamToFifo(mux); | ||||
|         sockets[mux]->sock_available--; | ||||
|         // ^^ One less character available after moving from modem's FIFO to our FIFO | ||||
|         // ^^ One less character available after moving from modem's FIFO to our | ||||
|         // FIFO | ||||
|       } | ||||
|       waitResponse();  // ends with an OK | ||||
|       DBG("### READ:", len, "from", mux); | ||||
| @@ -662,12 +485,15 @@ protected: | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size_t modemGetAvailable(uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     sendAT(GF("+QISTATE=1,"), mux); | ||||
|     //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|     // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|  | ||||
|     if (waitResponse(GF("+QISTATE:"))) | ||||
|       return false; | ||||
|     if (waitResponse(GF("+QISTATE:")) != 1) { return false; } | ||||
|  | ||||
|     streamSkipUntil(',');                           // Skip mux | ||||
|     streamSkipUntil(',');                           // Skip socket type | ||||
| @@ -682,19 +508,16 @@ protected: | ||||
|     return 2 == res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -703,14 +526,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -738,9 +561,9 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           } | ||||
|           data = ""; | ||||
|         } else if (data.endsWith(GF("CLOSED" GSM_NL))) { | ||||
|           int nl = data.lastIndexOf(GSM_NL, data.length()-8); | ||||
|           int coma = data.indexOf(',', nl+2); | ||||
|           int mux = data.substring(nl+2, coma).toInt(); | ||||
|           int nl   = data.lastIndexOf(GSM_NL, data.length() - 8); | ||||
|           int coma = data.indexOf(',', nl + 2); | ||||
|           int mux  = data.substring(nl + 2, coma).toInt(); | ||||
|           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||
|             sockets[mux]->sock_connected = false; | ||||
|           } | ||||
| @@ -749,38 +572,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&       stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientM95* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*   gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTM95_H_ | ||||
|   | ||||
| @@ -9,32 +9,23 @@ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientMC60_h | ||||
| #define TinyGsmClientMC60_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientMC60") | ||||
| #ifndef SRC_TINYGSMCLIENTMC60_H_ | ||||
| #define SRC_TINYGSMCLIENTMC60_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientMC60") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 6 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
|   SIM_ANTITHEFT_LOCKED = 3, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -43,26 +34,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| class TinyGsmMC60 | ||||
|     : public TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmMC60, READ_NO_CHECK, TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmMC60: public TinyGsmUTFSMS<TinyGsmMC60> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientMC60 : public GsmClient { | ||||
|     friend class TinyGsmMC60; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientMC60() {} | ||||
|  | ||||
|   GsmClient(TinyGsmMC60& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientMC60(TinyGsmMC60& modem, uint8_t mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmMC60* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -74,147 +63,121 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     at->sendAT(GF("+QICLOSE="), mux); | ||||
|     sock_connected = false; | ||||
|     at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), GF("CLOSE OK"), GF("ERROR")); | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(75000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_NO_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_NO_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       uint32_t startMillis = millis(); | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+QICLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse((maxWaitMs - (millis() - startMillis)), GF("CLOSED"), | ||||
|                        GF("CLOSE OK"), GF("ERROR")); | ||||
|     } | ||||
|     void stop() override { | ||||
|       stop(75000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmMC60*    at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   bool            sock_connected; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|  | ||||
| // class GsmClientSecure : public GsmClient | ||||
| // { | ||||
| // public: | ||||
| //   GsmClientSecure() {} | ||||
| // | ||||
| //   GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1) | ||||
| //     : GsmClient(modem, mux) | ||||
| //   {} | ||||
| // | ||||
| //   virtual ~GsmClientSecure(){} | ||||
| // | ||||
| // public: | ||||
| //   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
| //     stop(); | ||||
| //     TINY_GSM_YIELD(); | ||||
| //     rx.clear(); | ||||
| //     sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
| //     return sock_connected; | ||||
| //   } | ||||
| // }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmMC60(Stream& stream) | ||||
|     : stream(stream) | ||||
|   /* | ||||
|     class GsmClientSecureMC60 : public GsmClientMC60 | ||||
|     { | ||||
|     public: | ||||
|       GsmClientSecure() {} | ||||
|  | ||||
|       GsmClientSecure(TinyGsmMC60& modem, uint8_t mux = 1) | ||||
|        : GsmClient(modem, mux) | ||||
|       {} | ||||
|  | ||||
|  | ||||
|     public: | ||||
|       virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|         stop(); | ||||
|         TINY_GSM_YIELD(); | ||||
|         rx.clear(); | ||||
|         sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
|         return sock_connected; | ||||
|       } | ||||
|     }; | ||||
|  */ | ||||
|  | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmMC60(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     // sendAT(GF("&FZ"));  // Factory + Reset | ||||
|     // waitResponse(); | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| #else | ||||
|     sendAT(GF("+CMEE=0"));  // turn off error codes | ||||
| #endif | ||||
|     waitResponse(); | ||||
|  | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|  | ||||
|     // Enable network time synchronization | ||||
|     sendAT(GF("+QNITZ=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|     #if defined(TINY_GSM_MODEM_MC60) | ||||
|       return "Quectel MC60"; | ||||
|     #elif defined(TINY_GSM_MODEM_MC60E) | ||||
|       return "Quectel MC60E"; | ||||
|     #endif | ||||
|       return "Quectel MC60"; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_LISTEN() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|     sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+IPR=0"));   // Auto-baud | ||||
|     waitResponse(); | ||||
|     sendAT(GF("&W"));       // Write configuration | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   /* | ||||
|    * under development | ||||
|    */ | ||||
|   // bool hasSSL() { | ||||
|   // bool thisHasSSL() { | ||||
|   //   sendAT(GF("+QIPSSL=?")); | ||||
|   //   if (waitResponse(GF(GSM_NL "+CIPSSL:")) != 1) { | ||||
|   //     return false; | ||||
| @@ -222,75 +185,61 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   //   return waitResponse() == 1; | ||||
|   // } | ||||
|  | ||||
|   bool hasSSL() { | ||||
|     return false;  // TODO: For now | ||||
|   bool thisHasSSL() { | ||||
|     return false;  // TODO(?): Add SSL support | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     sendAT(GF("+CFUN=1,1")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000); | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+QPOWD=1")); | ||||
|     return waitResponse(GF("NORMAL POWER DOWN")) == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|   // When entering into sleep mode is enabled, DTR is pulled up, and WAKEUP_IN | ||||
|   // is pulled up, the module can directly enter into sleep mode.If entering | ||||
|   // into sleep mode is enabled, DTR is pulled down, and WAKEUP_IN is pulled | ||||
|   // down, there is a need to pull the DTR pin and the WAKEUP_IN pin up first, | ||||
|   // and then the module can enter into sleep mode. | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+QSCLK="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_SIMCCID_CCID() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|  protected: | ||||
|   SimStatus getSimStatusImpl(uint32_t timeout_ms = 10000L) { | ||||
|     for (uint32_t start = millis(); millis() - start < timeout_ms;) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); | ||||
|       int status = | ||||
|           waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), | ||||
|                        GF("NOT INSERTED"), GF("PH_SIM PIN"), GF("PH_SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
| @@ -304,43 +253,38 @@ TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     // select foreground context 0 = VIRTUAL_UART_1 | ||||
|     sendAT(GF("+QIFGCNT=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Select GPRS (=1) as the Bearer | ||||
|     sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, GF("\"")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Select GPRS (=1) as the Bearer | ||||
|     sendAT(GF("+QICSGP=1,\""), apn, GF("\",\""), user, GF("\",\""), pwd, | ||||
|            GF("\"")); | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Define PDP context - is this necessary? | ||||
|     // Define PDP context - is this necessary? | ||||
|     sendAT(GF("+CGDCONT=1,\"IP\",\""), apn, '"'); | ||||
|     waitResponse(); | ||||
|  | ||||
| @@ -350,56 +294,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|     // Select TCP/IP transfer mode - NOT transparent mode | ||||
|     sendAT(GF("+QIMODE=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Enable multiple TCP/IP connections | ||||
|     sendAT(GF("+QIMUX=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Start TCPIP Task and Set APN, User Name and Password | ||||
|     sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd,  "\"" ); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Start TCPIP Task and Set APN, User Name and Password | ||||
|     sendAT("+QIREGAPP=\"", apn, "\",\"", user, "\",\"", pwd, "\""); | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     //Activate GPRS/CSD Context | ||||
|     // Activate GPRS/CSD Context | ||||
|     sendAT(GF("+QIACT")); | ||||
|     if (waitResponse(60000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     // Check that we have a local IP address | ||||
|     if (localIP() == IPAddress(0,0,0,0)) { | ||||
|       return false; | ||||
|     } | ||||
|     if (localIP() == IPAddress(0, 0, 0, 0)) { return false; } | ||||
|  | ||||
|     //Set Method to Handle Received TCP/IP Data | ||||
|     // Set Method to Handle Received TCP/IP Data | ||||
|     // Mode=2 - Output a notification statement: | ||||
|     // “+QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen>” | ||||
|     sendAT(GF("+QINDI=2")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|     sendAT(GF("+QIDEACT")); | ||||
|   bool gprsDisconnectImpl() { | ||||
|     sendAT(GF("+QIDEACT"));  // Deactivate the bearer context | ||||
|     return waitResponse(60000L, GF("DEACT OK"), GF("ERROR")) == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+QILOCIP")); | ||||
|     stream.readStringUntil('\n'); | ||||
|     String res = stream.readStringUntil('\n'); | ||||
| @@ -407,61 +337,23 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow all of the phone call functions from the template | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow all template functions | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\"")); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
|     int dcs = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|  | ||||
|     if (dcs == 15) { | ||||
|       return TinyGsmDecodeHex8bit(hex); | ||||
|     } else if (dcs == 72) { | ||||
|       return TinyGsmDecodeHex16bit(hex); | ||||
|     } else { | ||||
|       return hex; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   /** Delete all SMS */ | ||||
|   bool deleteAllSMS() { | ||||
|     sendAT(GF("+QMGDA=6")); | ||||
|     if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1) ) { | ||||
|     if (waitResponse(waitResponse(60000L, GF("OK"), GF("ERROR")) == 1)) { | ||||
|       return true; | ||||
|     } | ||||
|     return false; | ||||
| @@ -470,118 +362,60 @@ TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can use CIPGSMLOC as inherited from the template | ||||
|  | ||||
|   String getGsmLocation() { | ||||
|     sendAT(GF("+CIPGSMLOC=1,1")); | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CIPGSMLOC:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   // Use: float vBatt = modem.getBattVoltage() / 1000.0; | ||||
|   uint16_t getBattVoltage() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     streamSkipUntil(','); // Skip battery charge status | ||||
|     streamSkipUntil(','); // Skip battery charge level | ||||
|     // return voltage in mV | ||||
|     uint16_t res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     streamSkipUntil(','); // Skip battery charge status | ||||
|     // Read battery charge level | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Read battery charge status | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     chargeState = stream.readStringUntil(',').toInt(); | ||||
|     percent = stream.readStringUntil(',').toInt(); | ||||
|     milliVolts = stream.readStringUntil('\n').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   float getTemperature() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  protected: | ||||
|   float getTemperatureImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 75) { | ||||
|    if (ssl) { | ||||
|      DBG("SSL not yet supported on this module!"); | ||||
|    } | ||||
|     if (ssl) { DBG("SSL not yet supported on this module!"); } | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|    sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, GF("\","), port); | ||||
|     int rsp = waitResponse(timeout_ms, | ||||
|                            GF("CONNECT OK" GSM_NL), | ||||
|                            GF("CONNECT FAIL" GSM_NL), | ||||
|                            GF("ALREADY CONNECT" GSM_NL)); | ||||
|     sendAT(GF("+QIOPEN="), mux, GF(",\""), GF("TCP"), GF("\",\""), host, | ||||
|            GF("\","), port); | ||||
|     int rsp = | ||||
|         waitResponse(timeout_ms, GF("CONNECT OK" GSM_NL), | ||||
|                      GF("CONNECT FAIL" GSM_NL), GF("ALREADY CONNECT" GSM_NL)); | ||||
|     return (1 == rsp); | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+QISEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "SEND OK")) != 1) { return 0; } | ||||
|  | ||||
|     bool allAcknowledged = false; | ||||
|     // bool failed = false; | ||||
|     while ( !allAcknowledged ) { | ||||
|       sendAT( GF("+QISACK")); | ||||
|     while (!allAcknowledged) { | ||||
|       sendAT(GF("+QISACK")); | ||||
|       if (waitResponse(5000L, GF(GSM_NL "+QISACK:")) != 1) { | ||||
|         return -1; | ||||
|       } else { | ||||
|         streamSkipUntil(','); /** Skip total */ | ||||
|         streamSkipUntil(','); /** Skip acknowledged data size */ | ||||
|         if ( stream.readStringUntil('\n').toInt() == 0 ) { | ||||
|         if (stream.readStringUntil('\n').toInt() == 0) { | ||||
|           allAcknowledged = true; | ||||
|         } | ||||
|       } | ||||
| @@ -591,16 +425,16 @@ protected: | ||||
|     // streamSkipUntil(','); // Skip mux | ||||
|     // return stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     return len;  // TODO | ||||
|     return len;  // TODO(?): verify len/ack | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     // TODO:  Does this work???? | ||||
|     // TODO(?):  Does this work???? | ||||
|     // AT+QIRD=<id>,<sc>,<sid>,<len> | ||||
|     // id = GPRS context number - 0, set in GPRS connect | ||||
|     // sc = roll in connection - 1, client of connection | ||||
|     // sid = index of connection - mux | ||||
|     // len = maximum length of data to send | ||||
|     // id = GPRS context number = 0, set in GPRS connect | ||||
|     // sc = role in connection = 1, client of connection | ||||
|     // sid = index of connection = mux | ||||
|     // len = maximum length of data to retrieve | ||||
|     sendAT(GF("+QIRD=0,1,"), mux, ',', (uint16_t)size); | ||||
|     // If it replies only OK for the write command, it means there is no | ||||
|     // received data in the buffer of the connection. | ||||
| @@ -615,15 +449,14 @@ protected: | ||||
|       // This is quite likely if the buffer is broken into packets - which may | ||||
|       // be different sizes. | ||||
|       // If so, make sure we make sure we re-set the amount of data available. | ||||
|       if (len < size) { | ||||
|           sockets[mux]->sock_available = len; | ||||
|       } | ||||
|       for (uint16_t i=0; i<len; i++) { | ||||
|         TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|       if (len < size) { sockets[mux]->sock_available = len; } | ||||
|       for (uint16_t i = 0; i < len; i++) { | ||||
|         moveCharFromStreamToFifo(mux); | ||||
|         sockets[mux]->sock_available--; | ||||
|         // ^^ One less character available after moving from modem's FIFO to our FIFO | ||||
|         // ^^ One less character available after moving from modem's FIFO to our | ||||
|         // FIFO | ||||
|       } | ||||
|       waitResponse(); | ||||
|       waitResponse();  // ends with an OK | ||||
|       DBG("### READ:", len, "from", mux); | ||||
|       return len; | ||||
|     } else { | ||||
| @@ -632,12 +465,15 @@ protected: | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   size_t modemGetAvailable(uint8_t) { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     sendAT(GF("+QISTATE=1,"), mux); | ||||
|     //+QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|     // +QISTATE: 0,"TCP","151.139.237.11",80,5087,4,1,0,0,"uart1" | ||||
|  | ||||
|     if (waitResponse(GF("+QISTATE:"))) | ||||
|       return false; | ||||
|     if (waitResponse(GF("+QISTATE:")) != 1) { return false; } | ||||
|  | ||||
|     streamSkipUntil(',');                           // Skip mux | ||||
|     streamSkipUntil(',');                           // Skip socket type | ||||
| @@ -652,19 +488,16 @@ protected: | ||||
|     return 2 == res; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -674,14 +507,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s, ",", r6s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -700,7 +533,8 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } else if (r6 && data.endsWith(r6)) { | ||||
|           index = 6; | ||||
|           goto finish; | ||||
|         } else if (data.endsWith(GF(GSM_NL "+QIRD:"))) {  // TODO:  QIRD? or QIRDI? | ||||
|         } else if (data.endsWith( | ||||
|                        GF(GSM_NL "+QIRD:"))) {  // TODO(?):  QIRD? or QIRDI? | ||||
|           // +QIRDI: <id>,<sc>,<sid>,<num>,<len>,< tlen> | ||||
|           streamSkipUntil(',');  // Skip the context | ||||
|           streamSkipUntil(',');  // Skip the role | ||||
| @@ -711,14 +545,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           // read the length of the current packet | ||||
|           int len_packet = stream.readStringUntil('\n').toInt(); | ||||
|           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||
|             sockets[mux]->sock_available = len_packet*num_packets; | ||||
|             sockets[mux]->sock_available = len_packet * num_packets; | ||||
|           } | ||||
|           data = ""; | ||||
|           DBG("### Got Data:", len, "on", mux); | ||||
|           DBG("### Got Data:", len_packet * num_packets, "on", mux); | ||||
|         } else if (data.endsWith(GF("CLOSED" GSM_NL))) { | ||||
|           int nl = data.lastIndexOf(GSM_NL, data.length()-8); | ||||
|           int coma = data.indexOf(',', nl+2); | ||||
|           int mux = data.substring(nl+2, coma).toInt(); | ||||
|           int nl   = data.lastIndexOf(GSM_NL, data.length() - 8); | ||||
|           int coma = data.indexOf(',', nl + 2); | ||||
|           int mux  = data.substring(nl + 2, coma).toInt(); | ||||
|           if (mux >= 0 && mux < TINY_GSM_MUX_COUNT && sockets[mux]) { | ||||
|             sockets[mux]->sock_connected = false; | ||||
|           } | ||||
| @@ -727,38 +561,37 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5, r6); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL, GsmConstStr r6=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL, GsmConstStr r6 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5, r6); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&        stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientMC60* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*    gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTMC60_H_ | ||||
|   | ||||
| @@ -6,31 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientSIM5360_h | ||||
| #define TinyGsmClientSIM5360_h | ||||
| #ifndef SRC_TINYGSMCLIENTSIM5360_H_ | ||||
| #define SRC_TINYGSMCLIENTSIM5360_H_ | ||||
|  | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
| //#define TINY_GSM_USE_HEX | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_USE_HEX | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 10 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,31 +31,25 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| enum TinyGSMDateTimeFormat { | ||||
|   DATE_FULL = 0, | ||||
|   DATE_TIME = 1, | ||||
|   DATE_DATE = 2 | ||||
| }; | ||||
| class TinyGsmSim5360 : public TinyGsmModem<TinyGsmSim5360, READ_AND_CHECK_SIZE, | ||||
|                                            TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmSim5360, READ_AND_CHECK_SIZE, | ||||
|                             TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmSim5360: public TinyGsmUTFSMS<TinyGsmSim5360> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSim5360 : public GsmClient { | ||||
|     friend class TinyGsmSim5360; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientSim5360() {} | ||||
|  | ||||
|   GsmClient(TinyGsmSim5360& modem, uint8_t mux = 0) { | ||||
|     explicit GsmClientSim5360(TinyGsmSim5360& modem, uint8_t mux = 0) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmSim5360* modem, uint8_t mux = 0) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -77,102 +63,116 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+CIPCLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmSim5360* at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  | ||||
|   // TODO(?): Add SSL support | ||||
|   /* | ||||
|   class GsmClientSecureSim5360 : public GsmClientSim5360 { | ||||
|    public: | ||||
|     GsmClientSecureSim5360() {} | ||||
|  | ||||
| public: | ||||
|     explicit GsmClientSecureSim5360(TinyGsmSim5360& modem, uint8_t mux = 1) | ||||
|       : GsmClientSim5360(modem, mux) {} | ||||
|  | ||||
|   TinyGsmSim5360(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, true, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|   }; | ||||
|   */ | ||||
|  | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmSim5360(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| #else | ||||
|     sendAT(GF("+CMEE=0"));  // turn off error codes | ||||
| #endif | ||||
|     waitResponse(); | ||||
|  | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|  | ||||
|     // Enable automatic time zome update | ||||
|     sendAT(GF("+CTZU=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   String getModemNameImpl() { | ||||
|     String name = "SIMCom SIM5360"; | ||||
|  | ||||
|     sendAT(GF("+CGMM")); | ||||
|     String res2; | ||||
|     if (waitResponse(1000L, res2) != 1) { | ||||
|       return name; | ||||
|     } | ||||
|     if (waitResponse(1000L, res2) != 1) { return name; } | ||||
|     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res2.replace("_", " "); | ||||
|     res2.trim(); | ||||
| @@ -182,61 +182,47 @@ public: | ||||
|     return name; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() | ||||
|  | ||||
|   bool factoryDefault() {  // these commands aren't supported | ||||
|   bool factoryDefaultImpl() {  // these commands aren't supported | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|     return false;  // TODO:  Module supports SSL, but not yet implemented | ||||
|   bool thisHasSSL() { | ||||
|     return false;  // TODO(>):  Module supports SSL, but not yet implemented | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+REBOOT")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000L);  // TODO:  Test this delay! | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000L);  // TODO(?):  Test this delay! | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPOF")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|   bool radioOffImpl() { | ||||
|     sendAT(GF("+CFUN=4")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) { | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+CSCLK="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
| @@ -244,85 +230,54 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| // Gets the CCID of a sim card via AT+CCID | ||||
|   String getSimCCID() { | ||||
|  protected: | ||||
|   // Gets the CCID of a sim card via AT+CCID | ||||
|   String getSimCCIDImpl() { | ||||
|     sendAT(GF("+CICCID")); | ||||
|     if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CGREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CGREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   String getNetworkModes() { | ||||
|     sendAT(GF("+CNMP=?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   String setNetworkMode(uint8_t mode) { | ||||
|     sendAT(GF("+CNMP="), mode); | ||||
|       if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { | ||||
|         return "OK"; | ||||
|       } | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect();  // Make sure we're not connected first | ||||
|  | ||||
|     // Define the PDP context | ||||
| @@ -336,7 +291,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     } | ||||
|  | ||||
|     // 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(); | ||||
|  | ||||
|     // The CGSOCKCONT commands define the "embedded" PDP context for TCP/IP | ||||
| @@ -367,21 +322,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     waitResponse(); | ||||
|  | ||||
|     // Configure socket parameters | ||||
|     //AT+CIPCCFG= [<NmRetry>][,[<DelayTm>][,[<Ack>][,[<errMode>][,]<HeaderType>][,[[<AsyncMode>][,[<TimeoutVal>]]]]]]]] | ||||
|     // NmRetry = number of retransmission to be made for an IP packet = 10 (default) | ||||
|     // DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default) | ||||
|     // AT+CIPCCFG= <NmRetry>, <DelayTm>, <Ack>, <errMode>, <HeaderType>, | ||||
|     //            <AsyncMode>, <TimeoutVal> | ||||
|     // NmRetry = number of retransmission to be made for an IP packet | ||||
|     //         = 10 (default) | ||||
|     // DelayTm = number of milliseconds to delay before outputting received data | ||||
|     //          = 0 (default) | ||||
|     // Ack = sets whether reporting a string “Send ok” = 0 (don't report) | ||||
|     // errMode = mode of reporting error result code = 0 (numberic values) | ||||
|     // HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,<link num>,<data length>”) | ||||
|     // AsyncMode = sets mode of executing commands = 0 (synchronous command executing) | ||||
|     // HeaderType = which data header of receiving data in multi-client mode | ||||
|     //            = 1 (“+RECEIVE,<link num>,<data length>”) | ||||
|     // AsyncMode = sets mode of executing commands | ||||
|     //           = 0 (synchronous command executing) | ||||
|     // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 | ||||
|     sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Configure timeouts for opening and closing sockets | ||||
|     // AT+CIPTIMEOUT=[<netopen_timeout>][, [<cipopen_timeout>][, [<cipsend_timeout>]]] | ||||
|     // AT+CIPTIMEOUT=<netopen_timeout>, <cipopen_timeout>, <cipsend_timeout> | ||||
|     sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); | ||||
|     waitResponse(); | ||||
|  | ||||
| @@ -393,45 +351,36 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     // We to ignore any immediate response and wait for the | ||||
|     // URC to show it's really connected. | ||||
|     sendAT(GF("+NETOPEN")); | ||||
|     if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|   bool gprsDisconnectImpl() { | ||||
|     // Close any open sockets | ||||
|     for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { | ||||
|       GsmClient *sock = sockets[mux]; | ||||
|       if (sock) { | ||||
|         sock->stop(); | ||||
|       } | ||||
|       GsmClientSim5360* sock = sockets[mux]; | ||||
|       if (sock) { sock->stop(); } | ||||
|     } | ||||
|  | ||||
|     // Stop the socket service | ||||
|     // Note: all sockets should be closed first - on 3G/4G models the sockets must be closed manually | ||||
|     // Note: all sockets should be closed first - on 3G/4G models the sockets | ||||
|     // must be closed manually | ||||
|     sendAT(GF("+NETCLOSE")); | ||||
|     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool isGprsConnected() { | ||||
|   bool isGprsConnectedImpl() { | ||||
|     sendAT(GF("+NETOPEN?")); | ||||
|     // May return +NETOPEN: 1, 0.  We just confirm that the first number is 1 | ||||
|     if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; } | ||||
|     waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+IPADDR"));  // Inquire Socket PDP address | ||||
|     // sendAT(GF("+CGPADDR=1")); // Show PDP address | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
| @@ -439,112 +388,59 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+IPADDR"));  // Inquire Socket PDP address | ||||
|     // sendAT(GF("+CGPADDR=1"));  // Show PDP address | ||||
|     String res; | ||||
|     if (waitResponse(10000L, res) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, res) != 1) { return ""; } | ||||
|     res.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res.replace(GSM_NL, ""); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|     // Select message format (1=text) | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     // Select TE character set | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\"")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
|     int dcs = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     if (dcs == 15) { | ||||
|       return TinyGsmDecodeHex8bit(hex); | ||||
|     } else if (dcs == 72) { | ||||
|       return TinyGsmDecodeHex16bit(hex); | ||||
|     } else { | ||||
|       return hex; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     // Get SMS service centre address | ||||
|     sendAT(GF("+AT+CSCA?")); | ||||
|     waitResponse(); | ||||
|     // Select message format (1=text) | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     // Send the message! | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   // Follows all messaging functions per template | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  | ||||
|   String getGsmLocation()  TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   // Use: float vBatt = modem.getBattVoltage() / 1000.0; | ||||
|   uint16_t getBattVoltage() { | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip battery charge status | ||||
|     streamSkipUntil(',');  // Skip battery charge level | ||||
|     // get voltage in VOLTS | ||||
| @@ -552,62 +448,32 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     // Return millivolts | ||||
| 	uint16_t res = voltage*1000; | ||||
|     uint16_t res = voltage * 1000; | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     streamSkipUntil(','); // Skip battery charge status | ||||
|     // Read battery charge level | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() { | ||||
|   bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                         uint16_t& milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     // Read battery charge status | ||||
|     int res = stream.readStringUntil(',').toInt(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|     sendAT(GF("+CBC?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return false; } | ||||
|     chargeState = stream.readStringUntil(',').toInt(); | ||||
|     percent     = stream.readStringUntil(',').toInt(); | ||||
|     // get voltage in VOLTS | ||||
|     float voltage = stream.readStringUntil('\n').toFloat(); | ||||
|     milliVolts = voltage*1000; | ||||
|     milliVolts    = voltage * 1000; | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // get temperature in degree celsius | ||||
|   float getTemperature() { | ||||
|   float getTemperatureImpl() { | ||||
|     // Enable Temparature Reading | ||||
|     sendAT(GF("+CMTE=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return 0; } | ||||
|     // Get Temparature Value | ||||
|     sendAT(GF("+CMTE?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CMTE:")) != 1) { return false; } | ||||
|     float res = stream.readStringUntil('\n').toFloat(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
| @@ -617,58 +483,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 15) { | ||||
|     if (ssl) { DBG("SSL not yet supported on this module!"); } | ||||
|     // Make sure we'll be getting data manually on this connection | ||||
|     sendAT(GF("+CIPRXGET=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|  | ||||
|     if (ssl) { | ||||
|         DBG("SSL not yet supported on this module!"); | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Establish a connection in multi-socket mode | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), port); | ||||
|     sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), | ||||
|            port); | ||||
|     // The reply is +CIPOPEN: ## of socket created | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     streamSkipUntil(',');  // Skip requested bytes to send | ||||
|     // TODO:  make sure requested and confirmed bytes match | ||||
|     // TODO(?):  make sure requested and confirmed bytes match | ||||
|     return stream.readStringUntil('\n').toInt(); | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
| #ifdef TINY_GSM_USE_HEX | ||||
|     sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } | ||||
| #else | ||||
|     sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } | ||||
| #endif | ||||
|     streamSkipUntil(',');  // Skip Rx mode 2/normal or 3/HEX | ||||
|     streamSkipUntil(',');  // Skip mux/cid (connecion id) | ||||
| @@ -676,16 +526,24 @@ protected: | ||||
|     //  ^^ Requested number of data bytes (1-1460 bytes)to be read | ||||
|     int len_confirmed = stream.readStringUntil('\n').toInt(); | ||||
|     // ^^ The data length which not read in the buffer | ||||
|     for (int i=0; i<len_requested; i++) { | ||||
|     for (int i = 0; i < len_requested; i++) { | ||||
|       uint32_t startMillis = millis(); | ||||
| #ifdef TINY_GSM_USE_HEX | ||||
|       while (stream.available() < 2 && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } | ||||
|       char buf[4] = { 0, }; | ||||
|       while (stream.available() < 2 && | ||||
|              (millis() - startMillis < sockets[mux]->_timeout)) { | ||||
|         TINY_GSM_YIELD(); | ||||
|       } | ||||
|       char buf[4] = { | ||||
|           0, | ||||
|       }; | ||||
|       buf[0] = stream.read(); | ||||
|       buf[1] = stream.read(); | ||||
|       char c = strtol(buf, NULL, 16); | ||||
| #else | ||||
|       while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } | ||||
|       while (!stream.available() && | ||||
|              (millis() - startMillis < sockets[mux]->_timeout)) { | ||||
|         TINY_GSM_YIELD(); | ||||
|       } | ||||
|       char c = stream.read(); | ||||
| #endif | ||||
|       sockets[mux]->rx.put(c); | ||||
| @@ -707,19 +565,15 @@ protected: | ||||
|       waitResponse(); | ||||
|     } | ||||
|     DBG("### Available:", result, "on", mux); | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
|   bool modemGetConnected(uint8_t mux) { | ||||
|     // Read the status of all sockets at once | ||||
|     sendAT(GF("+CIPCLOSE?")); | ||||
|     if (waitResponse(GF("+CIPCLOSE:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|     if (waitResponse(GF("+CIPCLOSE:")) != 1) { return false; } | ||||
|     for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|       // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state> | ||||
|       sockets[muxNo]->sock_connected = stream.parseInt(); | ||||
|     } | ||||
| @@ -727,19 +581,16 @@ protected: | ||||
|     return sockets[mux]->sock_connected; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -748,14 +599,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -804,45 +655,41 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           // Need to close all open sockets and release the network library. | ||||
|           // User will then need to reconnect. | ||||
|           DBG("### Network error!"); | ||||
|           if (!isGprsConnected()) { | ||||
|             gprsDisconnect(); | ||||
|           } | ||||
|           if (!isGprsConnected()) { gprsDisconnect(); } | ||||
|           data = ""; | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&           stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientSim5360* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*       gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTSIM5360_H_ | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,31 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientSIM7600_h | ||||
| #define TinyGsmClientSIM7600_h | ||||
| #ifndef SRC_TINYGSMCLIENTSIM7600_H_ | ||||
| #define SRC_TINYGSMCLIENTSIM7600_H_ | ||||
|  | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
| //#define TINY_GSM_USE_HEX | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_USE_HEX | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 10 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -39,31 +31,25 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| enum TinyGSMDateTimeFormat { | ||||
|   DATE_FULL = 0, | ||||
|   DATE_TIME = 1, | ||||
|   DATE_DATE = 2 | ||||
| }; | ||||
| class TinyGsmSim7600 : public TinyGsmModem<TinyGsmSim7600, READ_AND_CHECK_SIZE, | ||||
|                                            TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmSim7600, READ_AND_CHECK_SIZE, | ||||
|                             TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmSim7600: public TinyGsmUTFSMS<TinyGsmSim7600> | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSim7600 : public GsmClient { | ||||
|     friend class TinyGsmSim7600; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientSim7600() {} | ||||
|  | ||||
|   GsmClient(TinyGsmSim7600& modem, uint8_t mux = 0) { | ||||
|     explicit GsmClientSim7600(TinyGsmSim7600& modem, uint8_t mux = 0) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmSim7600* modem, uint8_t mux = 0) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -77,102 +63,92 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+CIPCLOSE="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmSim7600* at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmSim7600(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmSim7600(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| #else | ||||
|     sendAT(GF("+CMEE=0"));  // turn off error codes | ||||
| #endif | ||||
|     waitResponse(); | ||||
|  | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|  | ||||
|     // Enable automatic time zome update | ||||
|     sendAT(GF("+CTZU=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   String getModemNameImpl() { | ||||
|     String name = "SIMCom SIM7600"; | ||||
|  | ||||
|     sendAT(GF("+CGMM")); | ||||
|     String res2; | ||||
|     if (waitResponse(1000L, res2) != 1) { | ||||
|       return name; | ||||
|     } | ||||
|     if (waitResponse(1000L, res2) != 1) { return name; } | ||||
|     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res2.replace("_", " "); | ||||
|     res2.trim(); | ||||
| @@ -182,61 +158,47 @@ public: | ||||
|     return name; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() | ||||
|  | ||||
|   bool factoryDefault() {  // these commands aren't supported | ||||
|   bool factoryDefaultImpl() {  // these commands aren't supported | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|     return false;  // TODO:  Module supports SSL, but not yet implemented | ||||
|   bool thisHasSSL() { | ||||
|     return false;  // TODO(?):  Module supports SSL, but not yet implemented | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CRESET")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(5000L);  // TODO:  Test this delay! | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(5000L);  // TODO(?):  Test this delay! | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPOF")); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|   bool radioOffImpl() { | ||||
|     sendAT(GF("+CFUN=4")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) { | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+CSCLK="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
| @@ -244,85 +206,54 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| // Gets the CCID of a sim card via AT+CCID | ||||
|   String getSimCCID() { | ||||
|  protected: | ||||
|   // Gets the CCID of a sim card via AT+CCID | ||||
|   String getSimCCIDImpl() { | ||||
|     sendAT(GF("+CICCID")); | ||||
|     if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+ICCID:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CGREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CGREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
|  public: | ||||
|   String getNetworkModes() { | ||||
|     sendAT(GF("+CNMP=?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   String setNetworkMode(uint8_t mode) { | ||||
|     sendAT(GF("+CNMP="), mode); | ||||
|       if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { | ||||
|         return "OK"; | ||||
|       } | ||||
|     if (waitResponse(GF(GSM_NL "+CNMP:")) != 1) { return "OK"; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect();  // Make sure we're not connected first | ||||
|  | ||||
|     // Define the PDP context | ||||
| @@ -336,7 +267,7 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     } | ||||
|  | ||||
|     // 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(); | ||||
|  | ||||
|     // Configure TCP parameters | ||||
| @@ -350,21 +281,24 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     waitResponse(); | ||||
|  | ||||
|     // Configure socket parameters | ||||
|     //AT+CIPCCFG= [<NmRetry>][,[<DelayTm>][,[<Ack>][,[<errMode>][,]<HeaderType>][,[[<AsyncMode>][,[<TimeoutVal>]]]]]]]] | ||||
|     // NmRetry = number of retransmission to be made for an IP packet = 10 (default) | ||||
|     // DelayTm = number of milliseconds to delay to output data of Receiving = 0 (default) | ||||
|     // AT+CIPCCFG= <NmRetry>, <DelayTm>, <Ack>, <errMode>, <HeaderType>, | ||||
|     //            <AsyncMode>, <TimeoutVal> | ||||
|     // NmRetry = number of retransmission to be made for an IP packet | ||||
|     //         = 10 (default) | ||||
|     // DelayTm = number of milliseconds to delay before outputting received data | ||||
|     //          = 0 (default) | ||||
|     // Ack = sets whether reporting a string “Send ok” = 0 (don't report) | ||||
|     // errMode = mode of reporting error result code = 0 (numberic values) | ||||
|     // HeaderType = which data header of receiving data in multi-client mode = 1 (“+RECEIVE,<link num>,<data length>”) | ||||
|     // AsyncMode = sets mode of executing commands = 0 (synchronous command executing) | ||||
|     // HeaderType = which data header of receiving data in multi-client mode | ||||
|     //            = 1 (“+RECEIVE,<link num>,<data length>”) | ||||
|     // AsyncMode = sets mode of executing commands | ||||
|     //           = 0 (synchronous command executing) | ||||
|     // TimeoutVal = minimum retransmission timeout in milliseconds = 75000 | ||||
|     sendAT(GF("+CIPCCFG=10,0,0,0,1,0,75000")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Configure timeouts for opening and closing sockets | ||||
|     // AT+CIPTIMEOUT=[<netopen_timeout>][, [<cipopen_timeout>][, [<cipsend_timeout>]]] | ||||
|     // AT+CIPTIMEOUT=<netopen_timeout> <cipopen_timeout>, <cipsend_timeout> | ||||
|     sendAT(GF("+CIPTIMEOUT="), 75000, ',', 15000, ',', 15000); | ||||
|     waitResponse(); | ||||
|  | ||||
| @@ -376,38 +310,30 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     // We to ignore any immediate response and wait for the | ||||
|     // URC to show it's really connected. | ||||
|     sendAT(GF("+NETOPEN")); | ||||
|     if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(75000L, GF(GSM_NL "+NETOPEN: 0")) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|  | ||||
|   bool gprsDisconnectImpl() { | ||||
|     // Close all sockets and stop the socket service | ||||
|     // Note: On the LTE models, this single command closes all sockets and the service | ||||
|     // Note: On the LTE models, this single command closes all sockets and the | ||||
|     // service | ||||
|     sendAT(GF("+NETCLOSE")); | ||||
|     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(60000L, GF(GSM_NL "+NETCLOSE: 0")) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool isGprsConnected() { | ||||
|   bool isGprsConnectedImpl() { | ||||
|     sendAT(GF("+NETOPEN?")); | ||||
|     // May return +NETOPEN: 1, 0.  We just confirm that the first number is 1 | ||||
|     if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+NETOPEN: 1")) != 1) { return false; } | ||||
|     waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+IPADDR"));  // Inquire Socket PDP address | ||||
|     // sendAT(GF("+CGPADDR=1")); // Show PDP address | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
| @@ -415,120 +341,61 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+IPADDR"));  // Inquire Socket PDP address | ||||
|     // sendAT(GF("+CGPADDR=1"));  // Show PDP address | ||||
|     String res; | ||||
|     if (waitResponse(10000L, res) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, res) != 1) { return ""; } | ||||
|     res.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res.replace(GSM_NL, ""); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callNumber() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool dtmfSend() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool callHangupImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) { | ||||
|     // Select message format (1=text) | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     // Select TE character set | ||||
|     sendAT(GF("+CSCS=\"HEX\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CUSD=1,\""), code, GF("\"")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, GF(GSM_NL "+CUSD:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     stream.readStringUntil('"'); | ||||
|     String hex = stream.readStringUntil('"'); | ||||
|     stream.readStringUntil(','); | ||||
|     int dcs = stream.readStringUntil('\n').toInt(); | ||||
|  | ||||
|     if (dcs == 15) { | ||||
|       return TinyGsmDecodeHex8bit(hex); | ||||
|     } else if (dcs == 72) { | ||||
|       return TinyGsmDecodeHex16bit(hex); | ||||
|     } else { | ||||
|       return hex; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     // Get SMS service centre address | ||||
|     sendAT(GF("+AT+CSCA?")); | ||||
|     waitResponse(); | ||||
|     // Select message format (1=text) | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     //Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     // Send the message! | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|  protected: | ||||
|   // Follows all messaging functions per template | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  | ||||
|   String getGsmLocation()  TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // enable GPS | ||||
|   bool enableGPS() { | ||||
|     sendAT(GF("+CGPS=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool disableGPS() { | ||||
|     sendAT(GF("+CGPS=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // get the RAW GPS output | ||||
|   String getGPSraw() { | ||||
|     sendAT(GF("+CGNSSINFO=32")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
| @@ -536,68 +403,67 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   } | ||||
|  | ||||
|   // get GPS informations | ||||
|   bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0) { | ||||
|     //String buffer = ""; | ||||
|   bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0) { | ||||
|     // String buffer = ""; | ||||
|     bool fix = false; | ||||
|  | ||||
|     sendAT(GF("+CGNSSINFO")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSSINFO:")) != 1) { return false; } | ||||
|  | ||||
|     //stream.readStringUntil(','); // mode | ||||
|     if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; | ||||
|     stream.readStringUntil(','); //gps | ||||
|     // stream.readStringUntil(','); // mode | ||||
|     if (stream.readStringUntil(',').toInt() == 1) fix = true; | ||||
|     stream.readStringUntil(',');                                    // gps | ||||
|     stream.readStringUntil(',');                                    // glonass | ||||
|     stream.readStringUntil(',');                                    // beidu | ||||
|     *lat =  stream.readStringUntil(',').toFloat(); //lat | ||||
|     *lat = stream.readStringUntil(',').toFloat();                   // lat | ||||
|     stream.readStringUntil(',');                                    // N/S | ||||
|     *lon =  stream.readStringUntil(',').toFloat(); //lon | ||||
|     *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 (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 | ||||
|     stream.readStringUntil('\n'); | ||||
|  | ||||
|     waitResponse(); | ||||
|  | ||||
|     return fix; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|  protected: | ||||
|   // Use: float vBatt = modem.getBattVoltage() / 1000.0; | ||||
|   uint16_t getBattVoltage() { | ||||
|   uint16_t getBattVoltageImpl() { | ||||
|     sendAT(GF("+CBC")); | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CBC:")) != 1) { return 0; } | ||||
|  | ||||
|     // get voltage in VOLTS | ||||
|     float voltage = stream.readStringUntil('\n').toFloat(); | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     // Return millivolts | ||||
|     uint16_t res = voltage*1000; | ||||
|     uint16_t res = voltage * 1000; | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   int8_t getBattPercent()  TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   uint8_t getBattChargeState()  TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool getBattStats(uint8_t& chargeState, int8_t& percent, | ||||
|   bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                         uint16_t& milliVolts) { | ||||
|     chargeState = 0; | ||||
|     percent     = 0; | ||||
| @@ -606,11 +472,9 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   } | ||||
|  | ||||
|   // get temperature in degree celsius | ||||
|   uint16_t getTemperature() { | ||||
|   uint16_t getTemperatureImpl() { | ||||
|     sendAT(GF("+CPMUTEMP")); | ||||
|     if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CPMUTEMP:")) != 1) { return 0; } | ||||
|     // return temperature in C | ||||
|     uint16_t res = stream.readStringUntil('\n').toInt(); | ||||
|     // Wait for final OK | ||||
| @@ -621,58 +485,42 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t mux, | ||||
|                     bool ssl = false, int timeout_s = 15) { | ||||
|    if (ssl) { | ||||
|      DBG("SSL not yet supported on this module!"); | ||||
|    } | ||||
|     if (ssl) { DBG("SSL not yet supported on this module!"); } | ||||
|     // Make sure we'll be getting data manually on this connection | ||||
|     sendAT(GF("+CIPRXGET=1")); | ||||
|    if (waitResponse() != 1) { | ||||
|      return false; | ||||
|    } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     // Establish a connection in multi-socket mode | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     sendAT(GF("+CIPOPEN="), mux, ',', GF("\"TCP"), GF("\",\""), host, GF("\","), | ||||
|            port); | ||||
|     // The reply is +CIPOPEN: ## of socket created | ||||
|    if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { | ||||
|      return false; | ||||
|    } | ||||
|     if (waitResponse(timeout_ms, GF(GSM_NL "+CIPOPEN:")) != 1) { return false; } | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+CIPSEND="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     if (waitResponse(GF(">")) != 1) { return 0; } | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CIPSEND:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     streamSkipUntil(',');  // Skip requested bytes to send | ||||
|     // TODO:  make sure requested and confirmed bytes match | ||||
|     // TODO(?):  make sure requested and confirmed bytes match | ||||
|     return stream.readStringUntil('\n').toInt(); | ||||
|   } | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
| #ifdef TINY_GSM_USE_HEX | ||||
|     sendAT(GF("+CIPRXGET=3,"), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } | ||||
| #else | ||||
|     sendAT(GF("+CIPRXGET=2,"), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("+CIPRXGET:")) != 1) { return 0; } | ||||
| #endif | ||||
|     streamSkipUntil(',');  // Skip Rx mode 2/normal or 3/HEX | ||||
|     streamSkipUntil(',');  // Skip mux/cid (connecion id) | ||||
| @@ -680,16 +528,24 @@ protected: | ||||
|     //  ^^ Requested number of data bytes (1-1460 bytes)to be read | ||||
|     int len_confirmed = stream.readStringUntil('\n').toInt(); | ||||
|     // ^^ The data length which not read in the buffer | ||||
|     for (int i=0; i<len_requested; i++) { | ||||
|     for (int i = 0; i < len_requested; i++) { | ||||
|       uint32_t startMillis = millis(); | ||||
| #ifdef TINY_GSM_USE_HEX | ||||
|       while (stream.available() < 2 && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } | ||||
|       char buf[4] = { 0, }; | ||||
|       while (stream.available() < 2 && | ||||
|              (millis() - startMillis < sockets[mux]->_timeout)) { | ||||
|         TINY_GSM_YIELD(); | ||||
|       } | ||||
|       char buf[4] = { | ||||
|           0, | ||||
|       }; | ||||
|       buf[0] = stream.read(); | ||||
|       buf[1] = stream.read(); | ||||
|       char c = strtol(buf, NULL, 16); | ||||
| #else | ||||
|       while (!stream.available() && (millis() - startMillis < sockets[mux]->_timeout)) { TINY_GSM_YIELD(); } | ||||
|       while (!stream.available() && | ||||
|              (millis() - startMillis < sockets[mux]->_timeout)) { | ||||
|         TINY_GSM_YIELD(); | ||||
|       } | ||||
|       char c = stream.read(); | ||||
| #endif | ||||
|       sockets[mux]->rx.put(c); | ||||
| @@ -711,9 +567,7 @@ protected: | ||||
|       waitResponse(); | ||||
|     } | ||||
|     DBG("### Available:", result, "on", mux); | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     return result; | ||||
|   } | ||||
|  | ||||
| @@ -723,7 +577,7 @@ protected: | ||||
|     if (waitResponse(GF("+CIPCLOSE:")) != 1) { | ||||
|       // return false;  // TODO:  Why does this not read correctly? | ||||
|     } | ||||
|     for (int muxNo = 0; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|     for (int muxNo = 0; muxNo < TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|       // +CIPCLOSE:<link0_state>,<link1_state>,...,<link9_state> | ||||
|       sockets[muxNo]->sock_connected = stream.parseInt(); | ||||
|     } | ||||
| @@ -731,19 +585,16 @@ protected: | ||||
|     return sockets[mux]->sock_connected; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -752,14 +603,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -808,45 +659,41 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|           // Need to close all open sockets and release the network library. | ||||
|           // User will then need to reconnect. | ||||
|           DBG("### Network error!"); | ||||
|           if (!isGprsConnected()) { | ||||
|             gprsDisconnect(); | ||||
|           } | ||||
|           if (!isGprsConnected()) { gprsDisconnect(); } | ||||
|           data = ""; | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=NULL, GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&           stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientSim7600* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*       gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTSIM7600_H_ | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -6,34 +6,26 @@ | ||||
|  * @date     Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientSIM808_h | ||||
| #define TinyGsmClientSIM808_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientSIM808") | ||||
| #ifndef SRC_TINYGSMCLIENTSIM808_H_ | ||||
| #define SRC_TINYGSMCLIENTSIM808_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientSIM808") | ||||
|  | ||||
| #include <TinyGsmClientSIM800.h> | ||||
|  | ||||
|  | ||||
| class TinyGsmSim808: public TinyGsmSim800 | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmSim808(Stream& stream) | ||||
|     : TinyGsmSim800(stream) | ||||
|   {} | ||||
| class TinyGsmSim808 : public TinyGsmSim800 { | ||||
|  public: | ||||
|   explicit TinyGsmSim808(Stream& stream) : TinyGsmSim800(stream) {} | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  | ||||
|  public: | ||||
|   // enable GPS | ||||
|   bool enableGPS() { | ||||
|     // uint16_t state; | ||||
|  | ||||
|     sendAT(GF("+CGNSPWR=1")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
| @@ -42,9 +34,7 @@ public: | ||||
|     // uint16_t state; | ||||
|  | ||||
|     sendAT(GF("+CGNSPWR=0")); | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
| @@ -53,9 +43,7 @@ public: | ||||
|   // works only with ans SIM808 V2 | ||||
|   String getGPSraw() { | ||||
|     sendAT(GF("+CGNSINF")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
| @@ -64,23 +52,22 @@ public: | ||||
|  | ||||
|   // get GPS informations | ||||
|   // works only with ans SIM808 V2 | ||||
|   bool getGPS(float *lat, float *lon, float *speed=0, int *alt=0, int *vsat=0, int *usat=0) { | ||||
|     //String buffer = ""; | ||||
|   bool getGPS(float* lat, float* lon, float* speed = 0, int* alt = 0, | ||||
|               int* vsat = 0, int* usat = 0) { | ||||
|     // String buffer = ""; | ||||
|     // char chr_buffer[12]; | ||||
|     bool fix = false; | ||||
|  | ||||
|     sendAT(GF("+CGNSINF")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } | ||||
|  | ||||
|     stream.readStringUntil(',');  // mode | ||||
|     if ( stream.readStringUntil(',').toInt() == 1 ) fix = true; | ||||
|     stream.readStringUntil(','); //utctime | ||||
|     *lat =  stream.readStringUntil(',').toFloat(); //lat | ||||
|     *lon =  stream.readStringUntil(',').toFloat(); //lon | ||||
|     if (alt != NULL) *alt =  stream.readStringUntil(',').toFloat(); //lon | ||||
|     if (speed != NULL) *speed = stream.readStringUntil(',').toFloat(); //speed | ||||
|     if (stream.readStringUntil(',').toInt() == 1) fix = true; | ||||
|     stream.readStringUntil(',');                                    // utctime | ||||
|     *lat = stream.readStringUntil(',').toFloat();                   // lat | ||||
|     *lon = stream.readStringUntil(',').toFloat();                   // lon | ||||
|     if (alt != NULL) *alt = stream.readStringUntil(',').toFloat();  // lon | ||||
|     if (speed != NULL) *speed = stream.readStringUntil(',').toFloat();  // speed | ||||
|     stream.readStringUntil(','); | ||||
|     stream.readStringUntil(','); | ||||
|     stream.readStringUntil(','); | ||||
| @@ -88,8 +75,10 @@ public: | ||||
|     stream.readStringUntil(','); | ||||
|     stream.readStringUntil(','); | ||||
|     stream.readStringUntil(','); | ||||
|     if (vsat != NULL) *vsat = stream.readStringUntil(',').toInt(); //viewed satelites | ||||
|     if (usat != NULL) *usat = stream.readStringUntil(',').toInt(); //used satelites | ||||
|     if (vsat != NULL) | ||||
|       *vsat = stream.readStringUntil(',').toInt();  // viewed satelites | ||||
|     if (usat != NULL) | ||||
|       *usat = stream.readStringUntil(',').toInt();  // used satelites | ||||
|     stream.readStringUntil('\n'); | ||||
|  | ||||
|     waitResponse(); | ||||
| @@ -99,34 +88,31 @@ public: | ||||
|  | ||||
|   // get GPS time | ||||
|   // works only with SIM808 V2 | ||||
|   bool getGPSTime(int *year, int *month, int *day, int *hour, int *minute, int *second) { | ||||
|   bool getGPSTime(int* year, int* month, int* day, int* hour, int* minute, | ||||
|                   int* second) { | ||||
|     bool fix = false; | ||||
|     char chr_buffer[12]; | ||||
|     sendAT(GF("+CGNSINF")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CGNSINF:")) != 1) { return false; } | ||||
|  | ||||
|     for (int i = 0; i < 3; i++) { | ||||
|       String buffer = stream.readStringUntil(','); | ||||
|       buffer.toCharArray(chr_buffer, sizeof(chr_buffer)); | ||||
|       switch (i) { | ||||
|         case 0: | ||||
|           //mode | ||||
|           // mode | ||||
|           break; | ||||
|         case 1: | ||||
|           //fixstatus | ||||
|           if ( buffer.toInt() == 1 ) { | ||||
|             fix = buffer.toInt(); | ||||
|           } | ||||
|           // fixstatus | ||||
|           if (buffer.toInt() == 1) { fix = buffer.toInt(); } | ||||
|           break; | ||||
|         case 2: | ||||
|           *year = buffer.substring(0,4).toInt(); | ||||
|           *month = buffer.substring(4,6).toInt(); | ||||
|           *day = buffer.substring(6,8).toInt(); | ||||
|           *hour = buffer.substring(8,10).toInt(); | ||||
|           *minute = buffer.substring(10,12).toInt(); | ||||
|           *second = buffer.substring(12,14).toInt(); | ||||
|           *year   = buffer.substring(0, 4).toInt(); | ||||
|           *month  = buffer.substring(4, 6).toInt(); | ||||
|           *day    = buffer.substring(6, 8).toInt(); | ||||
|           *hour   = buffer.substring(8, 10).toInt(); | ||||
|           *minute = buffer.substring(10, 12).toInt(); | ||||
|           *second = buffer.substring(12, 14).toInt(); | ||||
|           break; | ||||
|  | ||||
|         default: | ||||
| @@ -135,7 +121,7 @@ public: | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|  | ||||
|     if (fix) { | ||||
| @@ -144,7 +130,6 @@ public: | ||||
|       return false; | ||||
|     } | ||||
|   } | ||||
|  | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTSIM808_H_ | ||||
|   | ||||
| @@ -6,32 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientSaraR4_h | ||||
| #define TinyGsmClientSaraR4_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientSaraR4") | ||||
| #ifndef SRC_TINYGSMCLIENTSARAR4_H_ | ||||
| #define SRC_TINYGSMCLIENTSARAR4_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientSaraR4") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 7 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -40,23 +31,24 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
| class TinyGsmSaraR4 : public TinyGsmModem<TinyGsmSaraR4, READ_AND_CHECK_SIZE, | ||||
|                                           TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmSaraR4, READ_AND_CHECK_SIZE, | ||||
|                             TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| class TinyGsmSaraR4 | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSaraR4 : public GsmClient { | ||||
|     friend class TinyGsmSaraR4; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientSaraR4() {} | ||||
|  | ||||
|     GsmClient(TinyGsmSaraR4& modem, uint8_t mux = 0) { init(&modem, mux); } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|     explicit GsmClientSaraR4(TinyGsmSaraR4& modem, uint8_t mux = 0) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|     bool init(TinyGsmSaraR4* modem, uint8_t mux = 0) { | ||||
|       this->at       = modem; | ||||
| @@ -71,8 +63,8 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -88,33 +80,25 @@ public: | ||||
|  | ||||
|       return sock_connected; | ||||
|     } | ||||
|   virtual int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|     String host; | ||||
|     host.reserve(16); | ||||
|     host += ip[0]; | ||||
|     host += "."; | ||||
|     host += ip[1]; | ||||
|     host += "."; | ||||
|     host += ip[2]; | ||||
|     host += "."; | ||||
|     host += ip[3]; | ||||
|     return connect(host.c_str(), port, timeout_s); | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|   virtual int connect(const char* host, uint16_t port) { | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 120); | ||||
|     } | ||||
|   virtual int connect(IPAddress ip, uint16_t port) { | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 120); | ||||
|     } | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     // We want to use an async socket close because the syncrhonous close of an | ||||
|     // open socket is INCREDIBLY SLOW and the modem can freeze up.  But we only | ||||
|     // attempt the async close if we already KNOW the socket is open because | ||||
|     // calling the async close on a closed socket and then attempting opening a | ||||
|     // new socket causes the board to lock up for 2-3 minutes and then finally | ||||
|     // return with a "new" socket that is immediately closed. | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       uint32_t startMillis = millis(); | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       // We want to use an async socket close because the syncrhonous close of | ||||
|       // an open socket is INCREDIBLY SLOW and the modem can freeze up.  But we | ||||
|       // only attempt the async close if we already KNOW the socket is open | ||||
|       // because calling the async close on a closed socket and then attempting | ||||
|       // opening a new socket causes the board to lock up for 2-3 minutes and | ||||
|       // then finally return with a "new" socket that is immediately closed. | ||||
|       // Attempting to close a socket that is already closed with a synchronous | ||||
|       // close quickly returns an error. | ||||
|       if (at->supportsAsyncSockets && sock_connected) { | ||||
| @@ -137,47 +121,30 @@ public: | ||||
|         sock_connected = false; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(135000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(135000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmSaraR4*  at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSecureR4 : public GsmClientSaraR4 { | ||||
|    public: | ||||
|     GsmClientSecureR4() {} | ||||
|  | ||||
|     explicit GsmClientSecureR4(TinyGsmSaraR4& modem, uint8_t mux = 1) | ||||
|         : GsmClientSaraR4(modem, mux) {} | ||||
|  | ||||
| class GsmClientSecure : public GsmClient | ||||
| { | ||||
| public: | ||||
|   GsmClientSecure() {} | ||||
|  | ||||
|   GsmClientSecure(TinyGsmSaraR4& modem, uint8_t mux = 1) | ||||
|     : GsmClient(modem, mux) | ||||
|   {} | ||||
|  | ||||
|   virtual ~GsmClientSecure(){} | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -191,34 +158,30 @@ public: | ||||
|       at->maintain(); | ||||
|       return sock_connected; | ||||
|     } | ||||
| }; | ||||
|   }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmSaraR4(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmSaraR4(Stream& stream) | ||||
|       : stream(stream), | ||||
|         has2GFallback(false), | ||||
|         supportsAsyncSockets(false) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { return init(pin); } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|  protected: | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| @@ -241,33 +204,33 @@ public: | ||||
|       supportsAsyncSockets = true; | ||||
|     } | ||||
|  | ||||
|     // Enable automatic time zome update | ||||
|     sendAT(GF("+CTZU=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided,return | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|     else { | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   // only difference in implementation is the warning on the wrong type | ||||
|   String getModemNameImpl() { | ||||
|     sendAT(GF("+CGMI")); | ||||
|     String res1; | ||||
|     if (waitResponse(1000L, res1) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|     } | ||||
|     if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; } | ||||
|     res1.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res1.trim(); | ||||
|  | ||||
|     sendAT(GF("+GMM")); | ||||
|     String res2; | ||||
|     if (waitResponse(1000L, res2) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|     } | ||||
|     if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; } | ||||
|     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res2.trim(); | ||||
|  | ||||
| @@ -281,108 +244,65 @@ public: | ||||
|     return name; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|   bool factoryDefaultImpl() { | ||||
|     sendAT(GF("&F"));  // Resets the current profile, other NVM not affected | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   // using +CFUN=15 instead of the more common CFUN=1,1 | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CFUN=15")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000);  // TODO:  Verify delay timing here | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000);  // TODO(?):  Verify delay timing here | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPWROFF")); | ||||
|     return waitResponse(40000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_SIMCCID_CCID() | ||||
|  | ||||
|   String getIMEI() { | ||||
|  protected: | ||||
|   // This uses "CGSN" instead of "GSN" | ||||
|   String getIMEIImpl() { | ||||
|     sendAT(GF("+CGSN")); | ||||
|     if (waitResponse(GF(GSM_NL)) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL)) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms;) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), | ||||
|                                 GF("NOT INSERTED")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     // Check first for EPS registration | ||||
|     sendAT(GF("+CEREG?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { | ||||
|       return REG_UNKNOWN; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CEREG:")) != 1) { return REG_UNKNOWN; } | ||||
|     streamSkipUntil(','); /* Skip format (0) */ | ||||
|     int status = stream.readStringUntil('\n').toInt(); | ||||
|     waitResponse(); | ||||
| @@ -394,64 +314,43 @@ TINY_GSM_MODEM_GET_SIMCCID_CCID() | ||||
|     } else { | ||||
|       // Otherwise, check generic network status | ||||
|       sendAT(GF("+CREG?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { | ||||
|         return REG_UNKNOWN; | ||||
|       } | ||||
|       if (waitResponse(GF(GSM_NL "+CREG:")) != 1) { return REG_UNKNOWN; } | ||||
|       streamSkipUntil(','); /* Skip format (0) */ | ||||
|       int status = stream.readStringUntil('\n').toInt(); | ||||
|       status = stream.readStringUntil('\n').toInt(); | ||||
|       waitResponse(); | ||||
|       return (RegStatus)status; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     if (s == REG_OK_HOME || s == REG_OK_ROAMING) | ||||
|       return true; | ||||
|     // else if (s == REG_UNKNOWN)  // for some reason, it can hang at unknown.. | ||||
|     //   return isGprsConnected(); | ||||
|     else return false; | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|  public: | ||||
|   bool setURAT(uint8_t urat) { | ||||
|     // AT+URAT=<SelectedAcT>[,<PreferredAct>[,<2ndPreferredAct>]] | ||||
|  | ||||
|     sendAT(GF("+COPS=2"));  // Deregister from network | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     sendAT(GF("+URAT="), urat);  // Radio Access Technology (RAT) selection | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     sendAT(GF("+COPS=0"));  // Auto-register to the network | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|     return restart(); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     // gprsDisconnect(); | ||||
|  | ||||
|     sendAT(GF("+CGATT=1"));  // attach to GPRS | ||||
|     if (waitResponse(360000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(360000L) != 1) { return false; } | ||||
|  | ||||
|     // Using CGDCONT sets up an "external" PCP context, i.e. a data connection | ||||
|     // using the external IP stack (e.g. Windows dial up) and PPP link over the | ||||
| @@ -468,21 +367,17 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     waitResponse(); | ||||
|  | ||||
|     sendAT(GF("+CGACT=1,1"));  // activate PDP profile/context 1 | ||||
|     if (waitResponse(150000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(150000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|   bool gprsDisconnectImpl() { | ||||
|     // Mark all the sockets as closed | ||||
|     // This ensures that asynchronously closed sockets are marked closed | ||||
|     for (int mux = 0; mux < TINY_GSM_MUX_COUNT; mux++) { | ||||
|       GsmClient* sock = sockets[mux]; | ||||
|       if (sock && sock->sock_connected) { | ||||
|         sock->sock_connected = false; | ||||
|       } | ||||
|       GsmClientSaraR4* sock = sockets[mux]; | ||||
|       if (sock && sock->sock_connected) { sock->sock_connected = false; } | ||||
|     } | ||||
|  | ||||
|     // sendAT(GF("+CGACT=0,1"));  // Deactivate PDP context 1 | ||||
| @@ -492,150 +387,116 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     } | ||||
|  | ||||
|     sendAT(GF("+CGATT=0"));  // detach from GPRS | ||||
|     if (waitResponse(360000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(360000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|     sendAT(GF("+CGPADDR")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGPADDR:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     streamSkipUntil(',');  // Skip context id | ||||
|     String res = stream.readStringUntil('\r'); | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  protected: | ||||
|   // Can follow the template in all function | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   // While the AT commands for call answer and hang-up are nominally supported, | ||||
|   // no voice calls are supported rendering them meaningless | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callNumberImpl(const String& number) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool callHangupImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CSCS=\"GSM\""));  // Set GSM default alphabet | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGF=1"));  // Set preferred message format to text mode | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\""));  // set the phone number | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text);  // Actually send the message | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|  protected: | ||||
|   String sendUSSDImpl(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool   sendSMS_UTF16Impl(const String& number, const void* text, | ||||
|                            size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  | ||||
|   String getGsmLocation() { | ||||
|  protected: | ||||
|   String getGsmLocationImpl() { | ||||
|     sendAT(GF("+ULOC=2,3,0,120,1")); | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|   int8_t getBattPercentImpl() { | ||||
|     sendAT(GF("+CIND?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; } | ||||
|  | ||||
|     int    res     = stream.readStringUntil(',').toInt(); | ||||
|     int8_t percent = res*20;  // return is 0-5 | ||||
|     int8_t percent = res * 20;  // return is 0-5 | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return percent; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|     percent = getBattPercent(); | ||||
|   bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                         uint16_t& milliVolts) { | ||||
|     chargeState = 0; | ||||
|     percent     = getBattPercent(); | ||||
|     milliVolts  = 0; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   float getTemperature() { | ||||
|   float getTemperatureImpl() { | ||||
|     // First make sure the temperature is set to be in celsius | ||||
|     sendAT(GF("+UTEMP=0"));  // Would use 1 for Fahrenheit | ||||
|     if (waitResponse() != 1) { | ||||
|       return (float)-9999; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return static_cast<float>(-9999); } | ||||
|     sendAT(GF("+UTEMP?")); | ||||
|     if (waitResponse(GF(GSM_NL "+UTEMP:")) != 1) { | ||||
|       return (float)-9999; | ||||
|       return static_cast<float>(-9999); | ||||
|     } | ||||
|     int16_t res  = stream.readStringUntil('\n').toInt(); | ||||
|     float   temp = -9999; | ||||
|     if (res != -1) { | ||||
|       temp = ((float)res)/10; | ||||
|     } | ||||
|     if (res != -1) { temp = (static_cast<float>(res)) / 10; } | ||||
|     return temp; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t* mux, | ||||
|                     bool ssl = false, int timeout_s = 120) { | ||||
|     uint32_t timeout_ms  = ((uint32_t)timeout_s) * 1000; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|  | ||||
|     // create a socket | ||||
|     sendAT(GF("+USOCR=6")); | ||||
|     // reply is +USOCR: ## of socket created | ||||
|     if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) { return false; } | ||||
|     *mux = stream.readStringUntil('\n').toInt(); | ||||
|     waitResponse(); | ||||
|  | ||||
| @@ -668,35 +529,33 @@ protected: | ||||
|       DBG("### Opening socket asynchronously!  Socket cannot be used until " | ||||
|           "the URC '+UUSOCO' appears."); | ||||
|       sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port, ",1"); | ||||
|       if (waitResponse(timeout_ms, GF(GSM_NL "+UUSOCO:")) == 1) { | ||||
|       if (waitResponse(timeout_ms - (millis() - startMillis), | ||||
|                        GF(GSM_NL "+UUSOCO:")) == 1) { | ||||
|         stream.readStringUntil(',').toInt();  // skip repeated mux | ||||
|         int connection_status = stream.readStringUntil('\n').toInt(); | ||||
|         DBG("### Waited", millis() - startMillis, "ms for socket to open"); | ||||
|         return (0 == connection_status); | ||||
|       } else { | ||||
|         DBG("### Waited", millis() - startMillis, "but never got socket open notice"); | ||||
|         DBG("### Waited", millis() - startMillis, | ||||
|             "but never got socket open notice"); | ||||
|         return false; | ||||
|       } | ||||
|     } else { | ||||
|       // use synchronous open | ||||
|       sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); | ||||
|       int rsp = waitResponse(timeout_ms); | ||||
|       int rsp = waitResponse(timeout_ms - (millis() - startMillis)); | ||||
|       return (1 == rsp); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+USOWR="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF("@")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("@")) != 1) { return 0; } | ||||
|     // 50ms delay, see AT manual section 25.10.4 | ||||
|     delay(50); | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     int sent = stream.readStringUntil('\n').toInt(); | ||||
|     waitResponse();  // sends back OK after the confirmation of number sent | ||||
| @@ -705,16 +564,12 @@ protected: | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     sendAT(GF("+USORD="), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     int len = stream.readStringUntil(',').toInt(); | ||||
|     streamSkipUntil('\"'); | ||||
|  | ||||
|     for (int i=0; i<len; i++) { | ||||
|       TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|     } | ||||
|     for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } | ||||
|     streamSkipUntil('\"'); | ||||
|     waitResponse(); | ||||
|     DBG("### READ:", len, "from", mux); | ||||
| @@ -735,9 +590,7 @@ protected: | ||||
|       // if (result) DBG("### DATA AVAILABLE:", result, "on", mux); | ||||
|       waitResponse(); | ||||
|     } | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     DBG("### AVAILABLE:", result, "on", mux); | ||||
|     return result; | ||||
|   } | ||||
| @@ -746,7 +599,7 @@ protected: | ||||
|     // NOTE:  Querying a closed socket gives an error "operation not allowed" | ||||
|     sendAT(GF("+USOCTL="), mux, ",10"); | ||||
|     uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:")); | ||||
|     if (res != 1) return false; | ||||
|     if (res != 1) { return false; } | ||||
|  | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     streamSkipUntil(',');  // Skip type | ||||
| @@ -767,20 +620,16 @@ protected: | ||||
|     return (result != 0); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1 = GFP(GSM_OK), | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -789,14 +638,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -843,12 +692,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, "/"); | ||||
| @@ -856,8 +703,7 @@ finish: | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1 = GFP(GSM_OK), | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
| @@ -865,20 +711,19 @@ finish: | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&          stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientSaraR4* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*      gsmNL = GSM_NL; | ||||
|   bool             has2GFallback; | ||||
|   bool             supportsAsyncSockets; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTSARAR4_H_ | ||||
|   | ||||
| @@ -6,30 +6,22 @@ | ||||
|  * @date       Jan 2019 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientSequansMonarch_h | ||||
| #define TinyGsmClientSequansMonarch_h | ||||
| #ifndef SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ | ||||
| #define SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_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_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -48,26 +40,27 @@ enum SocketStatus { | ||||
|   SOCK_OPENING                = 6, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmSequansMonarch | ||||
| { | ||||
|     : public TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE, | ||||
|                           TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmSequansMonarch, READ_AND_CHECK_SIZE, | ||||
|                             TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSequansMonarch : public GsmClient { | ||||
|     friend class TinyGsmSequansMonarch; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientSequansMonarch() {} | ||||
|  | ||||
|   GsmClient(TinyGsmSequansMonarch& modem, uint8_t mux = 1) { | ||||
|     explicit GsmClientSequansMonarch(TinyGsmSequansMonarch& modem, | ||||
|                                      uint8_t                mux = 1) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|     virtual ~GsmClient() {} | ||||
|  | ||||
|     bool init(TinyGsmSequansMonarch* modem, uint8_t mux = 1) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -83,65 +76,58 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|     virtual int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       if (sock_connected) stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
|       sock_connected = at->modemConnect(host, port, mux, false, timeout_s); | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+SQNSH="), mux); | ||||
|       sock_connected = false; | ||||
|       at->waitResponse(); | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmSequansMonarch* at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSecureSequansMonarch : public GsmClientSequansMonarch { | ||||
|    public: | ||||
|     GsmClientSecureSequansMonarch() {} | ||||
|  | ||||
|   class GsmClientSecure : public GsmClient { | ||||
| public: | ||||
|   GsmClientSecure() {} | ||||
|     explicit GsmClientSecureSequansMonarch(TinyGsmSequansMonarch& modem, | ||||
|                                            uint8_t                mux = 1) | ||||
|         : GsmClientSequansMonarch(modem, mux) {} | ||||
|  | ||||
|   GsmClientSecure(TinyGsmSequansMonarch& modem, uint8_t mux = 1) | ||||
|     : GsmClient(modem, mux) | ||||
|   {} | ||||
|  | ||||
|     virtual ~GsmClientSecure() {} | ||||
|  | ||||
| protected: | ||||
|    protected: | ||||
|     bool strictSSL = false; | ||||
|  | ||||
| public: | ||||
|     virtual int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -171,33 +157,27 @@ public: | ||||
|     void setStrictSSL(bool strict) { | ||||
|       strictSSL = strict; | ||||
|     } | ||||
|   }; | ||||
|  | ||||
| }; | ||||
|  | ||||
| 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,54 +189,32 @@ public: | ||||
|     DBG(GF("### Modem:"), getModemName()); | ||||
|  | ||||
|     // Make sure the module is enabled. Unlike others, the VZN20Q powers on | ||||
|     // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full functionality | ||||
|     // The module cannot even detect the sim card if the cellular functionality is disabled so | ||||
|     // unless we explicitly enable the functionality the init will fail. | ||||
|     // with CFUN=0 not CFUN=1 (that is, at minimum functionality instead of full | ||||
|     // functionality The module cannot even detect the sim card if the cellular | ||||
|     // functionality is disabled so unless we explicitly enable the | ||||
|     // functionality the init will fail. | ||||
|     sendAT(GF("+CFUN=1")); | ||||
|     waitResponse(); | ||||
|  | ||||
|     // Enable automatic time zome update | ||||
|     sendAT(GF("+CTZU=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return | ||||
|     // true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|     //   return "Sequans Monarch"; | ||||
|     sendAT(GF("+CGMI")); | ||||
|     String res1; | ||||
|     if (waitResponse(1000L, res1) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|   } | ||||
|     res1.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res1.trim(); | ||||
|  | ||||
|     sendAT(GF("+CGMM")); | ||||
|     String res2; | ||||
|     if (waitResponse(1000L, res2) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|     } | ||||
|     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res2.trim(); | ||||
|  | ||||
|     String name = res1 + String(' ') + res2; | ||||
|     return name; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
|   void maintain() { | ||||
|   void maintainImpl() { | ||||
|     for (int mux = 1; mux <= TINY_GSM_MUX_COUNT; mux++) { | ||||
|       GsmClient* sock = sockets[mux % TINY_GSM_MUX_COUNT]; | ||||
|       GsmClientSequansMonarch* sock = sockets[mux % TINY_GSM_MUX_COUNT]; | ||||
|       if (sock && sock->got_data) { | ||||
|         sock->got_data       = false; | ||||
|         sock->sock_available = modemGetAvailable(mux); | ||||
| @@ -264,78 +222,54 @@ TINY_GSM_MODEM_TEST_AT() | ||||
|         modemGetConnected(); | ||||
|       } | ||||
|     } | ||||
|     while (stream.available()) { | ||||
|       waitResponse(15, NULL, NULL); | ||||
|   } | ||||
|     while (stream.available()) { waitResponse(15, NULL, NULL); } | ||||
|   } | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|     sendAT(GF("&FZE0&W"));  // Factory + Reset + Echo Off + Write | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+IPR=0"));   // Auto-baud | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+IFC=0,0")); // No Flow Control | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+ICF=3,3")); // 8 data 0 parity 1 stop | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CSCLK=0")); // Disable Slow Clock | ||||
|     waitResponse(); | ||||
|     sendAT(GF("&W"));       // Write configuration | ||||
|     return waitResponse() == 1; | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     int res = waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")) ; | ||||
|     if (res != 1 && res != 3) { | ||||
|       return false; | ||||
|     } | ||||
|     int res = | ||||
|         waitResponse(20000L, GFP(GSM_OK), GFP(GSM_ERROR), GF("+SYSSTART")); | ||||
|     if (res != 1 && res != 3) { return false; } | ||||
|  | ||||
|     sendAT(GF("+CFUN=1,1")); | ||||
|     res = waitResponse(20000L, GF("+SYSSTART"), GFP(GSM_ERROR)); | ||||
|     if (res != 1 && res != 3) { | ||||
|       return false; | ||||
|     } | ||||
|     if (res != 1 && res != 3) { return false; } | ||||
|     delay(1000); | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     // NOTE:  The only way to turn the modem back on after this shutdown is with | ||||
|     // a hard reset | ||||
|     sendAT(GF("+SQNSSHDN")); | ||||
|     return waitResponse(); | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    When power saving is enabled, UART0 interface is activated with sleep mode support. | ||||
|    Module power state is controlled by RTS0 line.  When no activity on UART, CTS line | ||||
|    will be set to OFF state (driven high level) <timeout> milliseconds (100ms to 10s, | ||||
|    default 5s) after the last sent character, then module will go to sleep mode as soon | ||||
|    as DTE set RTS line to OFF state (driver high level). | ||||
|   */ | ||||
|   bool sleepEnable(bool enable = true) { | ||||
|   //  When power saving is enabled, UART0 interface is activated with sleep mode | ||||
|   //  support. Module power state is controlled by RTS0 line.  When no activity | ||||
|   //  on UART, CTS line will be set to OFF state (driven high level) <timeout> | ||||
|   //  milliseconds (100ms to 10s, default 5s) after the last sent character, | ||||
|   //  then module will go to sleep mode as soon as DTE set RTS line to OFF state | ||||
|   //  (driver high level). | ||||
|   bool sleepEnableImpl(bool enable = true) { | ||||
|     sendAT(GF("+SQNIPSCFG="), enable); | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
| @@ -343,68 +277,36 @@ TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
|   String getSimCCID() { | ||||
|  protected: | ||||
|   String getSimCCIDImpl() { | ||||
|     sendAT(GF("+SQNCCID")); | ||||
|     if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+SQNCCID:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_IMEI_GSN() | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|       case 2: | ||||
|       case 3:  return SIM_LOCKED; | ||||
|       case 1:  return SIM_READY; | ||||
|       default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CEREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CEREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     if (s == REG_OK_HOME || s == REG_OK_ROAMING) { | ||||
|       // DBG(F("connected with status:"), s); | ||||
|       return true; | ||||
|     } else { | ||||
|       return false; | ||||
|     return (s == REG_OK_HOME || s == REG_OK_ROAMING); | ||||
|   } | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     // Define the PDP context (This uses context #3!) | ||||
| @@ -423,122 +325,88 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|     // Attach to GPRS | ||||
|     sendAT(GF("+CGATT=1")); | ||||
|     if (waitResponse(60000L) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|   bool gprsDisconnectImpl() { | ||||
|     sendAT(GF("+CGATT=0")); | ||||
|     if (waitResponse(60000L) != 1) | ||||
|       return false; | ||||
|     if (waitResponse(60000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool isGprsConnected() { | ||||
|     sendAT(GF("+CGATT?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CGATT:")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     int res = stream.readStringUntil('\n').toInt(); | ||||
|     waitResponse(); | ||||
|     if (res != 1) | ||||
|       return false; | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+CGPADDR=3")); | ||||
|     if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(10000L, GF("+CGPADDR: 3,\"")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\"'); | ||||
|     waitResponse(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  protected: | ||||
|   bool callAnswerImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool | ||||
|   dtmfSendImpl(char cmd, int duration_ms = 100) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CMGF=1")); | ||||
|     waitResponse(); | ||||
|     // Set GSM 7 bit default alphabet (3GPP TS 23.038) | ||||
|     sendAT(GF("+CSCS=\"GSM\"")); | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\"")); | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text); | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Follows all messaging functions per template | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  protected: | ||||
|   String getGsmLocationImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   String getGsmLocation() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t getBattPercent() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool getBattStats(uint8_t& chargeState, int8_t& percent, | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   int8_t   getBattPercentImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t  getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   bool     getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                             uint16_t& milliVolts) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   float getTemperature() { | ||||
|   float getTemperatureImpl() { | ||||
|     sendAT(GF("+SMDTH")); | ||||
|     if (waitResponse(10000L, GF("+SMDTH: ")) != 1) { | ||||
|       return (float)-9999; | ||||
|       return static_cast<float>(-9999); | ||||
|     } | ||||
|     String res; | ||||
|     if (waitResponse(1000L, res) != 1) { | ||||
|       return (float)-9999; | ||||
|     } | ||||
|     if (res.indexOf("ERROR") >= 0) { | ||||
|       return (float)-9999; | ||||
|     } | ||||
|     if (waitResponse(1000L, res) != 1) { return static_cast<float>(-9999); } | ||||
|     if (res.indexOf("ERROR") >= 0) { return static_cast<float>(-9999); } | ||||
|     return res.toFloat(); | ||||
|   } | ||||
|  | ||||
| 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 startMillis = millis(); | ||||
|     uint32_t timeout_ms  = ((uint32_t)timeout_s) * 1000; | ||||
|  | ||||
|     if (ssl) { | ||||
| @@ -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++) { | ||||
| @@ -685,9 +553,7 @@ protected: | ||||
|     // six possible sockets. | ||||
|     sendAT(GF("+SQNSS")); | ||||
|     for (int muxNo = 1; muxNo <= TINY_GSM_MUX_COUNT; muxNo++) { | ||||
|       if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { | ||||
|         break; | ||||
|       }; | ||||
|       if (waitResponse(GFP(GSM_OK), GF(GSM_NL "+SQNSS: ")) != 2) { break; } | ||||
|       uint8_t status = 0; | ||||
|       // if (stream.readStringUntil(',').toInt() != muxNo) { // check the mux no | ||||
|       //   DBG("### Warning: misaligned mux numbers!"); | ||||
| @@ -704,26 +570,24 @@ protected: | ||||
|       // SOCK_LISTENING              = 4, | ||||
|       // SOCK_INCOMING               = 5, | ||||
|       // SOCK_OPENING                = 6, | ||||
|       sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = \ | ||||
|         ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && (status != SOCK_OPENING)); | ||||
|       sockets[muxNo % TINY_GSM_MUX_COUNT]->sock_connected = | ||||
|           ((status != SOCK_CLOSED) && (status != SOCK_INCOMING) && | ||||
|            (status != SOCK_OPENING)); | ||||
|     } | ||||
|     waitResponse();  // Should be an OK at the end | ||||
|     return sockets[mux % TINY_GSM_MUX_COUNT]->sock_connected; | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), GsmConstStr r3 = NULL, | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -732,14 +596,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -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: | ||||
|  protected: | ||||
|   Stream&                  stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientSequansMonarch* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*              gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTSEQUANSMONARCH_H_ | ||||
|   | ||||
| @@ -6,32 +6,23 @@ | ||||
|  * @date       Nov 2016 | ||||
|  */ | ||||
|  | ||||
| #ifndef TinyGsmClientUBLOX_h | ||||
| #define TinyGsmClientUBLOX_h | ||||
| //#pragma message("TinyGSM:  TinyGsmClientUBLOX") | ||||
| #ifndef SRC_TINYGSMCLIENTUBLOX_H_ | ||||
| #define SRC_TINYGSMCLIENTUBLOX_H_ | ||||
| // #pragma message("TinyGSM:  TinyGsmClientUBLOX") | ||||
|  | ||||
| //#define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #if !defined(TINY_GSM_RX_BUFFER) | ||||
|   #define TINY_GSM_RX_BUFFER 64 | ||||
| #endif | ||||
| // #define TINY_GSM_DEBUG Serial | ||||
|  | ||||
| #define TINY_GSM_MUX_COUNT 7 | ||||
|  | ||||
| #include <TinyGsmCommon.h> | ||||
| #include "TinyGsmCommon.h" | ||||
|  | ||||
| #define GSM_NL "\r\n" | ||||
| static const char GSM_OK[] TINY_GSM_PROGMEM        = "OK" GSM_NL; | ||||
| static const char GSM_ERROR[] TINY_GSM_PROGMEM     = "ERROR" GSM_NL; | ||||
| static const char GSM_CME_ERROR[] TINY_GSM_PROGMEM = GSM_NL "+CME ERROR:"; | ||||
|  | ||||
| enum SimStatus { | ||||
|   SIM_ERROR = 0, | ||||
|   SIM_READY = 1, | ||||
|   SIM_LOCKED = 2, | ||||
| }; | ||||
|  | ||||
| enum RegStatus { | ||||
|   REG_NO_RESULT    = -1, | ||||
|   REG_UNREGISTERED = 0, | ||||
|   REG_SEARCHING    = 2, | ||||
|   REG_DENIED       = 3, | ||||
| @@ -40,26 +31,25 @@ enum RegStatus { | ||||
|   REG_UNKNOWN      = 4, | ||||
| }; | ||||
|  | ||||
|  | ||||
| class TinyGsmUBLOX | ||||
| { | ||||
|     : public TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE, TINY_GSM_MUX_COUNT> { | ||||
|   friend class TinyGsmModem<TinyGsmUBLOX, READ_AND_CHECK_SIZE, | ||||
|                             TINY_GSM_MUX_COUNT>; | ||||
|  | ||||
| public: | ||||
|  | ||||
| class GsmClient : public Client | ||||
| { | ||||
|   /* | ||||
|    * Inner Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientUBLOX : public GsmClient { | ||||
|     friend class TinyGsmUBLOX; | ||||
|   typedef TinyGsmFifo<uint8_t, TINY_GSM_RX_BUFFER> RxFifo; | ||||
|  | ||||
| public: | ||||
|   GsmClient() {} | ||||
|    public: | ||||
|     GsmClientUBLOX() {} | ||||
|  | ||||
|   GsmClient(TinyGsmUBLOX& modem, uint8_t mux = 0) { | ||||
|     explicit GsmClientUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 0) { | ||||
|       init(&modem, mux); | ||||
|     } | ||||
|  | ||||
|   virtual ~GsmClient(){} | ||||
|  | ||||
|     bool init(TinyGsmUBLOX* modem, uint8_t mux = 0) { | ||||
|       this->at       = modem; | ||||
|       this->mux      = mux; | ||||
| @@ -73,8 +63,8 @@ public: | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -90,56 +80,46 @@ public: | ||||
|  | ||||
|       return sock_connected; | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port, int timeout_s) { | ||||
|       return connect(TinyGsmStringFromIp(ip).c_str(), port, timeout_s); | ||||
|     } | ||||
|     int connect(const char* host, uint16_t port) override { | ||||
|       return connect(host, port, 75); | ||||
|     } | ||||
|     int connect(IPAddress ip, uint16_t port) override { | ||||
|       return connect(ip, port, 75); | ||||
|     } | ||||
|  | ||||
| TINY_GSM_CLIENT_CONNECT_OVERLOADS() | ||||
|  | ||||
|   virtual void stop(uint32_t maxWaitMs) { | ||||
|     TINY_GSM_CLIENT_DUMP_MODEM_BUFFER() | ||||
|     void stop(uint32_t maxWaitMs) { | ||||
|       dumpModemBuffer(maxWaitMs); | ||||
|       at->sendAT(GF("+USOCL="), mux); | ||||
|       at->waitResponse();  // should return within 1s | ||||
|       sock_connected = false; | ||||
|     } | ||||
|  | ||||
|   virtual void stop() { stop(15000L); } | ||||
|  | ||||
| TINY_GSM_CLIENT_WRITE() | ||||
|  | ||||
| TINY_GSM_CLIENT_AVAILABLE_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_READ_WITH_BUFFER_CHECK() | ||||
|  | ||||
| TINY_GSM_CLIENT_PEEK_FLUSH_CONNECTED() | ||||
|     void stop() override { | ||||
|       stop(15000L); | ||||
|     } | ||||
|  | ||||
|     /* | ||||
|      * Extended API | ||||
|      */ | ||||
|  | ||||
|     String remoteIP() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   }; | ||||
|  | ||||
| private: | ||||
|   TinyGsmUBLOX*   at; | ||||
|   uint8_t         mux; | ||||
|   uint16_t        sock_available; | ||||
|   uint32_t        prev_check; | ||||
|   bool            sock_connected; | ||||
|   bool            got_data; | ||||
|   RxFifo          rx; | ||||
| }; | ||||
|   /* | ||||
|    * Inner Secure Client | ||||
|    */ | ||||
|  public: | ||||
|   class GsmClientSecureUBLOX : public GsmClientUBLOX { | ||||
|    public: | ||||
|     GsmClientSecureUBLOX() {} | ||||
|  | ||||
|     explicit GsmClientSecureUBLOX(TinyGsmUBLOX& modem, uint8_t mux = 1) | ||||
|         : GsmClientUBLOX(modem, mux) {} | ||||
|  | ||||
| class GsmClientSecure : public GsmClient | ||||
| { | ||||
| public: | ||||
|   GsmClientSecure() {} | ||||
|  | ||||
|   GsmClientSecure(TinyGsmUBLOX& modem, uint8_t mux = 1) | ||||
|     : GsmClient(modem, mux) | ||||
|   {} | ||||
|  | ||||
|   virtual ~GsmClientSecure(){} | ||||
|  | ||||
| public: | ||||
|   virtual int connect(const char *host, uint16_t port, int timeout_s) { | ||||
|    public: | ||||
|     int connect(const char* host, uint16_t port, int timeout_s) { | ||||
|       stop(); | ||||
|       TINY_GSM_YIELD(); | ||||
|       rx.clear(); | ||||
| @@ -153,14 +133,13 @@ public: | ||||
|       at->maintain(); | ||||
|       return sock_connected; | ||||
|     } | ||||
| }; | ||||
|   }; | ||||
|  | ||||
|  | ||||
| public: | ||||
|  | ||||
|   TinyGsmUBLOX(Stream& stream) | ||||
|     : stream(stream) | ||||
|   { | ||||
|   /* | ||||
|    * Constructor | ||||
|    */ | ||||
|  public: | ||||
|   explicit TinyGsmUBLOX(Stream& stream) : stream(stream) { | ||||
|     memset(sockets, 0, sizeof(sockets)); | ||||
|   } | ||||
|  | ||||
| @@ -168,21 +147,13 @@ public: | ||||
|    * Basic functions | ||||
|    */ | ||||
|  | ||||
|   bool begin(const char* pin = NULL) { | ||||
|     return init(pin); | ||||
|   } | ||||
|  | ||||
|   bool init(const char* pin = NULL) { | ||||
|   bool initImpl(const char* pin = NULL) { | ||||
|     DBG(GF("### TinyGSM Version:"), TINYGSM_VERSION); | ||||
|  | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|     if (!testAT()) { return false; } | ||||
|  | ||||
|     sendAT(GF("E0"));  // Echo Off | ||||
|     if (waitResponse() != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return false; } | ||||
|  | ||||
| #ifdef TINY_GSM_DEBUG | ||||
|     sendAT(GF("+CMEE=2"));  // turn on verbose error codes | ||||
| @@ -193,176 +164,127 @@ public: | ||||
|  | ||||
|     getModemName(); | ||||
|  | ||||
|     // Enable automatic time zome update | ||||
|     sendAT(GF("+CTZU=1")); | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|  | ||||
|     int ret = getSimStatus(); | ||||
|     // if the sim isn't ready and a pin has been provided, try to unlock the sim | ||||
|     if (ret != SIM_READY && pin != NULL && strlen(pin) > 0) { | ||||
|       simUnlock(pin); | ||||
|       return (getSimStatus() == SIM_READY); | ||||
|     } | ||||
|     // if the sim is ready, or it's locked but no pin has been provided, return true | ||||
|     else { | ||||
|     } else { | ||||
|       // if the sim is ready, or it's locked but no pin has been provided, | ||||
|       // return true | ||||
|       return (ret == SIM_READY || ret == SIM_LOCKED); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   String getModemName() { | ||||
|   String getModemNameImpl() { | ||||
|     sendAT(GF("+CGMI")); | ||||
|     String res1; | ||||
|     if (waitResponse(1000L, res1) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|     } | ||||
|     if (waitResponse(1000L, res1) != 1) { return "u-blox Cellular Modem"; } | ||||
|     res1.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res1.trim(); | ||||
|  | ||||
|     sendAT(GF("+GMM")); | ||||
|     String res2; | ||||
|     if (waitResponse(1000L, res2) != 1) { | ||||
|       return "u-blox Cellular Modem"; | ||||
|     } | ||||
|     if (waitResponse(1000L, res2) != 1) { return "u-blox Cellular Modem"; } | ||||
|     res2.replace(GSM_NL "OK" GSM_NL, ""); | ||||
|     res2.trim(); | ||||
|  | ||||
|     String name = res1 + String(' ') + res2; | ||||
|     DBG("### Modem:", name); | ||||
|     if (name.startsWith("u-blox SARA-R4") || name.startsWith("u-blox SARA-N4")) { | ||||
|     if (name.startsWith("u-blox SARA-R4") || | ||||
|         name.startsWith("u-blox SARA-N4")) { | ||||
|       DBG("### WARNING:  You are using the wrong TinyGSM modem!"); | ||||
|     } | ||||
|     else if (name.startsWith("u-blox SARA-N2")) { | ||||
|     } else if (name.startsWith("u-blox SARA-N2")) { | ||||
|       DBG("### SARA N2 NB-IoT modems not supported!"); | ||||
|     } | ||||
|  | ||||
|     return name; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_SET_BAUD_IPR() | ||||
|  | ||||
| TINY_GSM_MODEM_TEST_AT() | ||||
|  | ||||
| TINY_GSM_MODEM_MAINTAIN_CHECK_SOCKS() | ||||
|  | ||||
|   bool factoryDefault() { | ||||
|   bool factoryDefaultImpl() { | ||||
|     sendAT(GF("+UFACTORY=0,1"));  // No factory restore, erase NVM | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CFUN=16"));  // Reset | ||||
|     return waitResponse() == 1; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_INFO_ATI() | ||||
|  | ||||
|   bool hasSSL() { | ||||
|   bool thisHasSSL() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool hasWifi() { | ||||
|   bool thisHasWifi() { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   bool hasGPRS() { | ||||
|   bool thisHasGPRS() { | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Power functions | ||||
|    */ | ||||
|  | ||||
|   bool restart() { | ||||
|     if (!testAT()) { | ||||
|       return false; | ||||
|     } | ||||
|  protected: | ||||
|   bool restartImpl() { | ||||
|     if (!testAT()) { return false; } | ||||
|     sendAT(GF("+CFUN=16")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000);  // TODO:  Verify delay timing here | ||||
|     if (waitResponse(10000L) != 1) { return false; } | ||||
|     delay(3000);  // TODO(?):  Verify delay timing here | ||||
|     return init(); | ||||
|   } | ||||
|  | ||||
|   bool poweroff() { | ||||
|   bool powerOffImpl() { | ||||
|     sendAT(GF("+CPWROFF")); | ||||
|     return waitResponse(40000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool radioOff() { | ||||
|     sendAT(GF("+CFUN=0")); | ||||
|     if (waitResponse(10000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     delay(3000); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool sleepEnable(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   bool sleepEnableImpl(bool enable = true) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * SIM card functions | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_SIM_UNLOCK_CPIN() | ||||
|  | ||||
| TINY_GSM_MODEM_GET_SIMCCID_CCID() | ||||
|  | ||||
|   String getIMEI() { | ||||
|  protected: | ||||
|   String getIMEIImpl() { | ||||
|     sendAT(GF("+CGSN")); | ||||
|     if (waitResponse(GF(GSM_NL)) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL)) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   SimStatus getSimStatus(unsigned long timeout_ms = 10000L) { | ||||
|     for (unsigned long start = millis(); millis() - start < timeout_ms; ) { | ||||
|       sendAT(GF("+CPIN?")); | ||||
|       if (waitResponse(GF(GSM_NL "+CPIN:")) != 1) { | ||||
|         delay(1000); | ||||
|         continue; | ||||
|       } | ||||
|       int status = waitResponse(GF("READY"), GF("SIM PIN"), GF("SIM PUK"), GF("NOT INSERTED")); | ||||
|       waitResponse(); | ||||
|       switch (status) { | ||||
|         case 2: | ||||
|         case 3:  return SIM_LOCKED; | ||||
|         case 1:  return SIM_READY; | ||||
|         default: return SIM_ERROR; | ||||
|       } | ||||
|     } | ||||
|     return SIM_ERROR; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_REGISTRATION_XREG(CGREG) | ||||
|  | ||||
| TINY_GSM_MODEM_GET_OPERATOR_COPS() | ||||
|  | ||||
|   /* | ||||
|    * Generic network functions | ||||
|    */ | ||||
|  public: | ||||
|   RegStatus getRegistrationStatus() { | ||||
|     return (RegStatus)getRegistrationStatusXREG("CGREG"); | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_CSQ() | ||||
|  | ||||
|   bool isNetworkConnected() { | ||||
|  protected: | ||||
|   bool isNetworkConnectedImpl() { | ||||
|     RegStatus s = getRegistrationStatus(); | ||||
|     if (s == REG_OK_HOME || s == REG_OK_ROAMING) | ||||
|       return true; | ||||
|     else if (s == REG_UNKNOWN)  // for some reason, it can hang at unknown.. | ||||
|       return isGprsConnected(); | ||||
|     else return false; | ||||
|     else | ||||
|       return false; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|  | ||||
|   /* | ||||
|    * GPRS functions | ||||
|    */ | ||||
|  | ||||
|   bool gprsConnect(const char* apn, const char* user = NULL, const char* pwd = NULL) { | ||||
|  protected: | ||||
|   bool gprsConnectImpl(const char* apn, const char* user = NULL, | ||||
|                        const char* pwd = NULL) { | ||||
|     gprsDisconnect(); | ||||
|  | ||||
|     sendAT(GF("+CGATT=1"));  // attach to GPRS | ||||
|     if (waitResponse(360000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(360000L) != 1) { return false; } | ||||
|  | ||||
|     // Setting up the PSD profile/PDP context with the UPSD commands sets up an | ||||
|     // "internal" PDP context, i.e. a data connection using the internal IP | ||||
| @@ -394,9 +316,10 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     // Packet switched data action | ||||
|     // AT+UPSDA=<profile_id>,<action> | ||||
|     // profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context) | ||||
|     // action = 3: activate; it activates a PDP context with the specified profile, | ||||
|     // using the current parameters | ||||
|     sendAT(GF("+UPSDA=0,3")); // Activate the PDP context associated with profile 0 | ||||
|     // action = 3: activate; it activates a PDP context with the specified | ||||
|     // profile, using the current parameters | ||||
|     sendAT(GF( | ||||
|         "+UPSDA=0,3"));  // Activate the PDP context associated with profile 0 | ||||
|     if (waitResponse(360000L) != 1) {  // Should return ok | ||||
|       return false; | ||||
|     } | ||||
| @@ -406,7 +329,8 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     // for the active PDP context associated with the specified PSD profile. | ||||
|     // AT+UPSND=<profile_id>,<param_tag> | ||||
|     // profile_id = 0: PSD profile identifier, in range 0-6 (NOT PDP context) | ||||
|     // param_tag = 8: PSD profile status: if the profile is active the return value is 1, 0 otherwise | ||||
|     // param_tag = 8: PSD profile status: if the profile is active the return | ||||
|     // value is 1, 0 otherwise | ||||
|     sendAT(GF("+UPSND=0,8"));  // Check if PSD profile 0 is now active | ||||
|     int res = waitResponse(GF(",8,1"), GF(",8,0")); | ||||
|     waitResponse();  // Should return another OK | ||||
| @@ -424,138 +348,109 @@ TINY_GSM_MODEM_WAIT_FOR_NETWORK() | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   bool gprsDisconnect() { | ||||
|     sendAT(GF("+UPSDA=0,4"));  // Deactivate the PDP context associated with profile 0 | ||||
|     if (waitResponse(360000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|   bool gprsDisconnectImpl() { | ||||
|     sendAT(GF( | ||||
|         "+UPSDA=0,4"));  // Deactivate the PDP context associated with profile 0 | ||||
|     if (waitResponse(360000L) != 1) { return false; } | ||||
|  | ||||
|     sendAT(GF("+CGATT=0"));  // detach from GPRS | ||||
|     if (waitResponse(360000L) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     if (waitResponse(360000L) != 1) { return false; } | ||||
|  | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
| TINY_GSM_MODEM_GET_GPRS_IP_CONNECTED() | ||||
|  | ||||
|   /* | ||||
|    * IP Address functions | ||||
|    */ | ||||
|  | ||||
|   String getLocalIP() { | ||||
|  protected: | ||||
|   String getLocalIPImpl() { | ||||
|     sendAT(GF("+UPSND=0,0")); | ||||
|     if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+UPSND:")) != 1) { return ""; } | ||||
|     streamSkipUntil(',');   // Skip PSD profile | ||||
|     streamSkipUntil('\"');  // Skip request type | ||||
|     String res = stream.readStringUntil('\"'); | ||||
|     if (waitResponse() != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse() != 1) { return ""; } | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   IPAddress localIP() { | ||||
|     return TinyGsmIpFromString(getLocalIP()); | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * Phone Call functions | ||||
|    */ | ||||
|  | ||||
|   bool setGsmBusy(bool busy = true) TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool callAnswer() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callNumber(const String& number) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool callHangup() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  protected: | ||||
|   // Can follow all of the phone call functions from the template | ||||
|  | ||||
|   /* | ||||
|    * Messaging functions | ||||
|    */ | ||||
|  | ||||
|   String sendUSSD(const String& code) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   bool sendSMS(const String& number, const String& text) { | ||||
|     sendAT(GF("+CSCS=\"GSM\""));  // Set GSM default alphabet | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGF=1"));  // Set preferred message format to text mode | ||||
|     waitResponse(); | ||||
|     sendAT(GF("+CMGS=\""), number, GF("\""));  // set the phone number | ||||
|     if (waitResponse(GF(">")) != 1) { | ||||
|       return false; | ||||
|     } | ||||
|     stream.print(text);  // Actually send the message | ||||
|     stream.write((char)0x1A); | ||||
|     stream.flush(); | ||||
|     return waitResponse(60000L) == 1; | ||||
|   } | ||||
|  | ||||
|   bool sendSMS_UTF16(const String& number, const void* text, size_t len) TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|  protected: | ||||
|   // Can follow all template functions | ||||
|  | ||||
|   /* | ||||
|    * Location functions | ||||
|    */ | ||||
|  | ||||
|   String getGsmLocation() { | ||||
|  protected: | ||||
|   String getGsmLocationImpl() { | ||||
|     sendAT(GF("+ULOC=2,3,0,120,1")); | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { | ||||
|       return ""; | ||||
|     } | ||||
|     if (waitResponse(30000L, GF(GSM_NL "+UULOC:")) != 1) { return ""; } | ||||
|     String res = stream.readStringUntil('\n'); | ||||
|     waitResponse(); | ||||
|     res.trim(); | ||||
|     return res; | ||||
|   } | ||||
|  | ||||
|   /* | ||||
|    * GPS location functions | ||||
|    */ | ||||
|  public: | ||||
|   // No functions of this type supported | ||||
|  | ||||
|   /* | ||||
|    * Time functions | ||||
|    */ | ||||
|  protected: | ||||
|   // Can follow the standard CCLK function in the template | ||||
|  | ||||
|   /* | ||||
|    * Battery & temperature functions | ||||
|    */ | ||||
|  protected: | ||||
|   uint16_t getBattVoltageImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   uint16_t getBattVoltage() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   int8_t getBattPercent() { | ||||
|   int8_t getBattPercentImpl() { | ||||
|     sendAT(GF("+CIND?")); | ||||
|     if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+CIND:")) != 1) { return 0; } | ||||
|  | ||||
|     int    res     = stream.readStringUntil(',').toInt(); | ||||
|     int8_t percent = res*20;  // return is 0-5 | ||||
|     int8_t percent = res * 20;  // return is 0-5 | ||||
|     // Wait for final OK | ||||
|     waitResponse(); | ||||
|     return percent; | ||||
|   } | ||||
|  | ||||
|   uint8_t getBattChargeState() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|   uint8_t getBattChargeStateImpl() TINY_GSM_ATTR_NOT_AVAILABLE; | ||||
|  | ||||
|   bool getBattStats(uint8_t &chargeState, int8_t &percent, uint16_t &milliVolts) { | ||||
|   bool getBattStatsImpl(uint8_t& chargeState, int8_t& percent, | ||||
|                         uint16_t& milliVolts) { | ||||
|     chargeState = 0; | ||||
|     percent     = getBattPercent(); | ||||
|     milliVolts  = 0; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // This would only available for a small number of modules in this group (TOBY-L) | ||||
|   float getTemperature() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|   // This would only available for a small number of modules in this group | ||||
|   // (TOBY-L) | ||||
|   float getTemperatureImpl() TINY_GSM_ATTR_NOT_IMPLEMENTED; | ||||
|  | ||||
|   /* | ||||
|    * Client related functions | ||||
|    */ | ||||
|  | ||||
| protected: | ||||
|  | ||||
|  protected: | ||||
|   bool modemConnect(const char* host, uint16_t port, uint8_t* mux, | ||||
|                     bool ssl = false, int timeout_s = 120) | ||||
|   { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s)*1000; | ||||
|                     bool ssl = false, int timeout_s = 120) { | ||||
|     uint32_t timeout_ms = ((uint32_t)timeout_s) * 1000; | ||||
|     sendAT(GF("+USOCR=6"));  // create a socket | ||||
|     if (waitResponse(GF(GSM_NL "+USOCR:")) != 1) {  // reply is +USOCR: ## of socket created | ||||
|     if (waitResponse(GF(GSM_NL "+USOCR:")) != | ||||
|         1) {  // reply is +USOCR: ## of socket created | ||||
|       return false; | ||||
|     } | ||||
|     *mux = stream.readStringUntil('\n').toInt(); | ||||
| @@ -571,8 +466,8 @@ protected: | ||||
|     waitResponse(); | ||||
|  | ||||
|     // Enable KEEPALIVE, 30 sec | ||||
|     //sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); | ||||
|     //waitResponse(); | ||||
|     // sendAT(GF("+USOSO="), *mux, GF(",6,2,30000")); | ||||
|     // waitResponse(); | ||||
|  | ||||
|     // connect on the allocated socket | ||||
|     sendAT(GF("+USOCO="), *mux, ",\"", host, "\",", port); | ||||
| @@ -582,16 +477,12 @@ protected: | ||||
|  | ||||
|   int16_t modemSend(const void* buff, size_t len, uint8_t mux) { | ||||
|     sendAT(GF("+USOWR="), mux, ',', (uint16_t)len); | ||||
|     if (waitResponse(GF("@")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF("@")) != 1) { return 0; } | ||||
|     // 50ms delay, see AT manual section 25.10.4 | ||||
|     delay(50); | ||||
|     stream.write((uint8_t*)buff, len); | ||||
|     stream.write(reinterpret_cast<const uint8_t*>(buff), len); | ||||
|     stream.flush(); | ||||
|     if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+USOWR:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     int sent = stream.readStringUntil('\n').toInt(); | ||||
|     waitResponse();  // sends back OK after the confirmation of number sent | ||||
| @@ -600,16 +491,12 @@ protected: | ||||
|  | ||||
|   size_t modemRead(size_t size, uint8_t mux) { | ||||
|     sendAT(GF("+USORD="), mux, ',', (uint16_t)size); | ||||
|     if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { | ||||
|       return 0; | ||||
|     } | ||||
|     if (waitResponse(GF(GSM_NL "+USORD:")) != 1) { return 0; } | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     int len = stream.readStringUntil(',').toInt(); | ||||
|     streamSkipUntil('\"'); | ||||
|  | ||||
|     for (int i=0; i<len; i++) { | ||||
|       TINY_GSM_MODEM_STREAM_TO_MUX_FIFO_WITH_DOUBLE_TIMEOUT | ||||
|     } | ||||
|     for (int i = 0; i < len; i++) { moveCharFromStreamToFifo(mux); } | ||||
|     streamSkipUntil('\"'); | ||||
|     waitResponse(); | ||||
|     DBG("### READ:", len, "from", mux); | ||||
| @@ -630,9 +517,7 @@ protected: | ||||
|       // if (result) DBG("### DATA AVAILABLE:", result, "on", mux); | ||||
|       waitResponse(); | ||||
|     } | ||||
|     if (!result) { | ||||
|       sockets[mux]->sock_connected = modemGetConnected(mux); | ||||
|     } | ||||
|     if (!result) { sockets[mux]->sock_connected = modemGetConnected(mux); } | ||||
|     DBG("### AVAILABLE:", result, "on", mux); | ||||
|     return result; | ||||
|   } | ||||
| @@ -641,8 +526,7 @@ protected: | ||||
|     // NOTE:  Querying a closed socket gives an error "operation not allowed" | ||||
|     sendAT(GF("+USOCTL="), mux, ",10"); | ||||
|     uint8_t res = waitResponse(GF(GSM_NL "+USOCTL:")); | ||||
|     if (res != 1) | ||||
|       return false; | ||||
|     if (res != 1) { return false; } | ||||
|  | ||||
|     streamSkipUntil(',');  // Skip mux | ||||
|     streamSkipUntil(',');  // Skip type | ||||
| @@ -663,19 +547,16 @@ protected: | ||||
|     return (result != 0); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  | ||||
|   /* | ||||
|    Utilities | ||||
|    * Utilities | ||||
|    */ | ||||
|  | ||||
| TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|  | ||||
|   // TODO: Optimize this! | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, String& data, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|  public: | ||||
|   // TODO(vshymanskyy): Optimize this! | ||||
|   uint8_t | ||||
|   waitResponse(uint32_t timeout_ms, String& data, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     /*String r1s(r1); r1s.trim(); | ||||
|     String r2s(r2); r2s.trim(); | ||||
|     String r3s(r3); r3s.trim(); | ||||
| @@ -684,14 +565,14 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|     DBG("### ..:", r1s, ",", r2s, ",", r3s, ",", r4s, ",", r5s);*/ | ||||
|     data.reserve(64); | ||||
|     int      index       = 0; | ||||
|     unsigned long startMillis = millis(); | ||||
|     uint32_t startMillis = millis(); | ||||
|     do { | ||||
|       TINY_GSM_YIELD(); | ||||
|       while (stream.available() > 0) { | ||||
|         TINY_GSM_YIELD(); | ||||
|         int a = stream.read(); | ||||
|         if (a <= 0) continue;  // Skip 0x00 bytes, just in case | ||||
|         data += (char)a; | ||||
|         data += static_cast<char>(a); | ||||
|         if (r1 && data.endsWith(r1)) { | ||||
|           index = 1; | ||||
|           goto finish; | ||||
| @@ -729,38 +610,36 @@ TINY_GSM_MODEM_STREAM_UTILITIES() | ||||
|         } | ||||
|       } | ||||
|     } while (millis() - startMillis < timeout_ms); | ||||
| finish: | ||||
|   finish: | ||||
|     if (!index) { | ||||
|       data.trim(); | ||||
|       if (data.length()) { | ||||
|         DBG("### Unhandled:", data); | ||||
|       } | ||||
|       if (data.length()) { DBG("### Unhandled:", data); } | ||||
|       data = ""; | ||||
|     } | ||||
|     //data.replace(GSM_NL, "/"); | ||||
|     //DBG('<', index, '>', data); | ||||
|     // data.replace(GSM_NL, "/"); | ||||
|     // DBG('<', index, '>', data); | ||||
|     return index; | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, | ||||
|                        GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t waitResponse(uint32_t timeout_ms, GsmConstStr r1 = GFP(GSM_OK), | ||||
|                        GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3 = GFP(GSM_CME_ERROR), | ||||
|                        GsmConstStr r4 = NULL, GsmConstStr r5 = NULL) { | ||||
|     String data; | ||||
|     return waitResponse(timeout_ms, data, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
|   uint8_t waitResponse(GsmConstStr r1=GFP(GSM_OK), GsmConstStr r2=GFP(GSM_ERROR), | ||||
|                        GsmConstStr r3=GFP(GSM_CME_ERROR), GsmConstStr r4=NULL, GsmConstStr r5=NULL) | ||||
|   { | ||||
|   uint8_t | ||||
|   waitResponse(GsmConstStr r1 = GFP(GSM_OK), GsmConstStr r2 = GFP(GSM_ERROR), | ||||
|                GsmConstStr r3 = GFP(GSM_CME_ERROR), GsmConstStr r4 = NULL, | ||||
|                GsmConstStr r5 = NULL) { | ||||
|     return waitResponse(1000, r1, r2, r3, r4, r5); | ||||
|   } | ||||
|  | ||||
| public: | ||||
|  protected: | ||||
|   Stream&         stream; | ||||
|  | ||||
| protected: | ||||
|   GsmClient*    sockets[TINY_GSM_MUX_COUNT]; | ||||
|   GsmClientUBLOX* sockets[TINY_GSM_MUX_COUNT]; | ||||
|   const char*     gsmNL = GSM_NL; | ||||
| }; | ||||
|  | ||||
| #endif | ||||
| #endif  // SRC_TINYGSMCLIENTUBLOX_H_ | ||||
|   | ||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1592
									
								
								src/TinyGsmCommon.h
									
									
									
									
									
								
							
							
						
						
									
										1592
									
								
								src/TinyGsmCommon.h
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -25,23 +25,35 @@ void setup() { | ||||
|  | ||||
| void loop() { | ||||
|  | ||||
|   // Test the start/restart functions | ||||
|   modem.restart(); | ||||
|   // Test the basic functions | ||||
|   modem.init(); | ||||
|   modem.begin(); | ||||
|   modem.setBaud(115200); | ||||
|   modem.testAT(); | ||||
|   modem.factoryDefault(); | ||||
|   modem.getModemInfo(); | ||||
|   modem.getModemName(); | ||||
|   modem.maintain(); | ||||
|   modem.hasSSL(); | ||||
|   modem.hasWifi(); | ||||
|   modem.hasGPRS(); | ||||
|  | ||||
|   // Test Power functions | ||||
|   modem.restart(); | ||||
|   // modem.sleepEnable(); | ||||
|   modem.radioOff(); | ||||
|   modem.poweroff(); | ||||
|  | ||||
|   // Test the SIM card functions | ||||
|   #if defined(TINY_GSM_MODEM_HAS_GPRS) | ||||
|   modem.getSimCCID(); | ||||
|   modem.getIMEI(); | ||||
|   modem.getSimStatus(); | ||||
|   modem.getRegistrationStatus(); | ||||
|   modem.getOperator(); | ||||
|   #endif | ||||
|  | ||||
|  | ||||
|   // Test the Networking functions | ||||
|   modem.getRegistrationStatus(); | ||||
|   modem.getSignalQuality(); | ||||
|   modem.localIP(); | ||||
|  | ||||
| @@ -61,7 +73,7 @@ void loop() { | ||||
|   client.print(String("Host: ") + server + "\r\n"); | ||||
|   client.print("Connection: close\r\n\r\n"); | ||||
|  | ||||
|   unsigned long timeout = millis(); | ||||
|   uint32_t timeout = millis(); | ||||
|   while (client.connected() && millis() - timeout < 10000L) { | ||||
|     while (client.available()) { | ||||
|       client.read(); | ||||
| @@ -77,4 +89,9 @@ void loop() { | ||||
|   #if defined(TINY_GSM_MODEM_HAS_WIFI) | ||||
|     modem.networkDisconnect(); | ||||
|   #endif | ||||
|  | ||||
|   // Test battery and temperature functions | ||||
|   // modem.getBattVoltage(); | ||||
|   // modem.getBattPercent(); | ||||
|   // modem.getTemperature(); | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user