├── .gitattributes ├── .gitignore ├── ISSUE_TEMPLATE.md ├── LICENSE.md ├── README.md ├── examples ├── 00_Register_Operator │ └── 00_Register_Operator.ino ├── 01_SMS_Send │ └── 01_SMS_Send.ino ├── 02_TCP_Send_Hologram │ └── 02_TCP_Send_Hologram.ino ├── 03_TCP_Receive_Hologram │ └── 03_TCP_Receive_Hologram.ino ├── 04_Hologram_Data_Feed │ └── 04_Hologram_Data_Feed.ino ├── 05_GPS_Request │ └── 05_GPS_Request.ino ├── 06_GPS_GPRMS │ └── 06_GPS_GPRMS.ino ├── Network_Info │ └── Network_Info.ino └── Serial_Passthrough │ └── Serial_Passthrough.ino ├── keywords.txt ├── library.properties └── src ├── SparkFun_LTE_Shield_Arduino_Library.cpp └── SparkFun_LTE_Shield_Arduino_Library.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # IDE settings directories/folders 2 | .vscode/ 3 | 4 | # Windows image file caches 5 | Thumbs.db 6 | ehthumbs.db 7 | 8 | # Folder config file 9 | Desktop.ini 10 | 11 | # Recycle Bin used on file shares 12 | $RECYCLE.BIN/ 13 | 14 | # Windows Installer files 15 | *.cab 16 | *.msi 17 | *.msm 18 | *.msp 19 | 20 | # Windows shortcuts 21 | *.lnk 22 | 23 | # C build files 24 | _build 25 | *.elf 26 | *.hex 27 | *.exe 28 | 29 | # Arduino CLI config file 30 | *.yml 31 | Makefile 32 | 33 | # ========================= 34 | # Operating System Files 35 | # ========================= 36 | 37 | # OSX 38 | # ========================= 39 | 40 | .DS_Store 41 | .AppleDouble 42 | .LSOverride 43 | 44 | # Thumbnails 45 | ._* 46 | 47 | # Files that might appear in the root of a volume 48 | .DocumentRevisions-V100 49 | .fseventsd 50 | .Spotlight-V100 51 | .TemporaryItems 52 | .Trashes 53 | .VolumeIcon.icns 54 | 55 | # Directories potentially created on remote AFP share 56 | .AppleDB 57 | .AppleDesktop 58 | Network Trash Folder 59 | Temporary Items 60 | .apdisk 61 | 62 | # Test examples 63 | test -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Subject of the issue 2 | Describe your issue here. 3 | 4 | ### Your workbench 5 | * What platform are you using? 6 | * What version of the device are you using? Is there a firmware version? 7 | * How is the device wired to your platform? 8 | * How is everything being powered? 9 | * Are there any additional details that may help us help you? 10 | 11 | ### Steps to reproduce 12 | Tell us how to reproduce this issue. Please post stripped down example code demonstrating your issue to a gist. 13 | 14 | ### Expected behaviour 15 | Tell us what should happen 16 | 17 | ### Actual behaviour 18 | Tell us what happens instead -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | SparkFun License Information 2 | ============================ 3 | 4 | SparkFun uses two different licenses for our files — one for hardware and one for code. 5 | 6 | Hardware 7 | --------- 8 | 9 | **SparkFun hardware is released under [Creative Commons Share-alike 4.0 International](http://creativecommons.org/licenses/by-sa/4.0/).** 10 | 11 | Note: This is a human-readable summary of (and not a substitute for) the [license](http://creativecommons.org/licenses/by-sa/4.0/legalcode). 12 | 13 | You are free to: 14 | 15 | Share — copy and redistribute the material in any medium or format 16 | Adapt — remix, transform, and build upon the material 17 | for any purpose, even commercially. 18 | The licensor cannot revoke these freedoms as long as you follow the license terms. 19 | Under the following terms: 20 | 21 | Attribution — You must give appropriate credit, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use. 22 | ShareAlike — If you remix, transform, or build upon the material, you must distribute your contributions under the same license as the original. 23 | No additional restrictions — You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits. 24 | Notices: 25 | 26 | You do not have to comply with the license for elements of the material in the public domain or where your use is permitted by an applicable exception or limitation. 27 | No warranties are given. The license may not give you all of the permissions necessary for your intended use. For example, other rights such as publicity, privacy, or moral rights may limit how you use the material. 28 | 29 | 30 | Code 31 | -------- 32 | 33 | **SparkFun code, firmware, and software is released under the MIT License(http://opensource.org/licenses/MIT).** 34 | 35 | The MIT License (MIT) 36 | 37 | Copyright (c) 2016 SparkFun Electronics 38 | 39 | Permission is hereby granted, free of charge, to any person obtaining a copy 40 | of this software and associated documentation files (the "Software"), to deal 41 | in the Software without restriction, including without limitation the rights 42 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 43 | copies of the Software, and to permit persons to whom the Software is 44 | furnished to do so, subject to the following conditions: 45 | 46 | The above copyright notice and this permission notice shall be included in all 47 | copies or substantial portions of the Software. 48 | 49 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 50 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 51 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 52 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 53 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 54 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 55 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | SparkFun LTE Shield Arduino Library 2 | ============================== 3 | 4 | [![SparkFun LTE CAT M1/NB-IoT Shield - SARA-R4](https://cdn.sparkfun.com//assets/parts/1/3/3/0/9/14997-SparkFun_LTE_CAT_M1_NB-IoT_Shield_-_SARA-R4-01a.jpg)](https://www.sparkfun.com/products/14997) 5 | 6 | [*SparkFun LTE CAT M1/NB-IoT Shield - SARA-R4 (CEL-14997)*](https://www.sparkfun.com/products/14997) 7 | 8 | Arduino library for the SparkFun LTE CAT M1/NB-IoT Shield 9 | 10 | Repository Contents 11 | ------------------- 12 | 13 | * **/examples** - Example sketches for the library (.ino). Run these from the Arduino IDE. 14 | * **/src** - Source files for the library (.cpp, .h). 15 | * **keywords.txt** - Keywords from this library that will be highlighted in the Arduino IDE. 16 | * **library.properties** - General library properties for the Arduino package manager. 17 | 18 | Documentation 19 | ------------- 20 | 21 | * **[Installing an Arduino Library Guide](https://learn.sparkfun.com/tutorials/installing-an-arduino-library)** - Basic information on how to install an Arduino library. 22 | * **[Product Repository](https://github.com/sparkfun/LTE_Cat_M1_Shield)** - Main repository (including hardware files). 23 | * **[Hookup Guide](https://learn.sparkfun.com/tutorials/lte-cat-m1nb-iot-shield-hookup-guide)** - Basic hookup guide. 24 | 25 | License Information 26 | ------------------- 27 | 28 | This product is _**open source**_! 29 | 30 | Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round! 31 | 32 | Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. 33 | 34 | Distributed as-is; no warranty is given. 35 | 36 | - Your friends at SparkFun. 37 | -------------------------------------------------------------------------------- /examples/00_Register_Operator/00_Register_Operator.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Register your LTE Shield/SIM combo on a mobile network operator 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: November 19, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to initialize your Cat M1/NB-IoT shield, and 12 | connect it to a mobile network operator (Verizon, AT&T, T-Mobile, etc.). 13 | 14 | Before beginning, you may need to adjust the mobile network operator (MNO) 15 | setting on line 45. See comments above that line to help select either 16 | Verizon, T-Mobile, AT&T or others. 17 | 18 | You may also need to set an APN on line 51 -- e.g. "hologram" 19 | 20 | Hardware Connections: 21 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 22 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 23 | the "ARDUINO" position. 24 | */ 25 | 26 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 27 | #include 28 | 29 | // We need to pass a Serial or SoftwareSerial object to the LTE Shield 30 | // library. Below creates a SoftwareSerial object on the standard LTE 31 | // Shield RX/TX pins: 32 | // Note: if you're using an Arduino board with a dedicated hardware 33 | // serial port, comment out the line below. (Also see note in setup) 34 | SoftwareSerial lteSerial(8, 9); 35 | 36 | // Create a LTE_Shield object to be used throughout the sketch: 37 | LTE_Shield lte; 38 | 39 | // To support multiple architectures, serial ports are abstracted here. 40 | // By default, they'll support AVR's like the Arduino Uno and Redboard 41 | // For example, on a SAMD21 board SerialMonitor can be changed to SerialUSB 42 | // and LTEShieldSerial can be set to Serial1 (hardware serial port on 0/1) 43 | #define SerialMonitor Serial 44 | #define LTEShieldSerial lteSerial 45 | 46 | // Network operator can be set to either: 47 | // MNO_SW_DEFAULT -- DEFAULT 48 | // MNO_ATT -- AT&T 49 | // MNO_VERIZON -- Verizon 50 | // MNO_TELSTRA -- Telstra 51 | // MNO_TMO -- T-Mobile 52 | const mobile_network_operator_t MOBILE_NETWORK_OPERATOR = MNO_SW_DEFAULT; 53 | const String MOBILE_NETWORK_STRINGS[] = {"Default", "SIM_ICCD", "AT&T", "VERIZON", 54 | "TELSTRA", "T-Mobile", "CT"}; 55 | 56 | // APN -- Access Point Name. Gateway between GPRS MNO 57 | // and another computer network. E.g. "hologram 58 | const String APN = "hologram"; 59 | 60 | // This defines the size of the ops struct array. Be careful making 61 | // this much bigger than ~5 on an Arduino Uno. To narrow the operator 62 | // list, set MOBILE_NETWORK_OPERATOR to AT&T, Verizeon etc. instead 63 | // of MNO_SW_DEFAULT. 64 | #define MAX_OPERATORS 5 65 | 66 | #define DEBUG_PASSTHROUGH_ENABLED 67 | 68 | void setup() { 69 | int opsAvailable; 70 | struct operator_stats ops[MAX_OPERATORS]; 71 | String currentOperator = ""; 72 | bool newConnection = true; 73 | 74 | SerialMonitor.begin(9600); 75 | while (!SerialMonitor) ; // For boards with built-in USB 76 | 77 | SerialMonitor.println(F("Initializing the LTE Shield...")); 78 | SerialMonitor.println(F("...this may take ~25 seconds if the shield is off.")); 79 | SerialMonitor.println(F("...it may take ~5 seconds if it just turned on.")); 80 | 81 | // Call lte.begin and pass it your Serial/SoftwareSerial object to 82 | // communicate with the LTE Shield. 83 | // Note: If you're using an Arduino with a dedicated hardware serial 84 | // port, you may instead slide "Serial" into this begin call. 85 | if ( lte.begin(LTEShieldSerial, 9600) ) { 86 | SerialMonitor.println(F("LTE Shield connected!\r\n")); 87 | } else { 88 | SerialMonitor.println("Unable to initialize the shield."); 89 | while(1) ; 90 | } 91 | 92 | // First check to see if we're already connected to an operator: 93 | if (lte.getOperator(¤tOperator) == LTE_SHIELD_SUCCESS) { 94 | SerialMonitor.print(F("Already connected to: ")); 95 | SerialMonitor.println(currentOperator); 96 | // If already connected provide the option to type y to connect to new operator 97 | SerialMonitor.println(F("Press y to connect to a new operator, or any other key to continue.\r\n")); 98 | while (!SerialMonitor.available()) ; 99 | if (SerialMonitor.read() != 'y') { 100 | newConnection = false; 101 | } 102 | while (SerialMonitor.available()) SerialMonitor.read(); 103 | } 104 | 105 | if (newConnection) { 106 | // Set MNO to either Verizon, T-Mobile, AT&T, Telstra, etc. 107 | // This will narrow the operator options during our scan later 108 | SerialMonitor.println(F("Setting mobile-network operator")); 109 | if (lte.setNetwork(MOBILE_NETWORK_OPERATOR)) { 110 | SerialMonitor.print(F("Set mobile network operator to ")); 111 | SerialMonitor.println(MOBILE_NETWORK_STRINGS[MOBILE_NETWORK_OPERATOR] + "\r\n"); 112 | } else { 113 | SerialMonitor.println(F("Error setting MNO. Try cycling power to the shield/Arduino.")); 114 | while (1) ; 115 | } 116 | 117 | // Set the APN -- Access Point Name -- e.g. "hologram" 118 | SerialMonitor.println(F("Setting APN...")); 119 | if (lte.setAPN(APN) == LTE_SHIELD_SUCCESS) { 120 | SerialMonitor.println(F("APN successfully set.\r\n")); 121 | } else { 122 | SerialMonitor.println(F("Error setting APN. Try cycling power to the shield/Arduino.")); 123 | while (1) ; 124 | } 125 | 126 | // Wait for user to press button before initiating network scan. 127 | SerialMonitor.println(F("Press any key scan for networks..")); 128 | serialWait(); 129 | 130 | SerialMonitor.println(F("Scanning for operators...this may take up to 3 minutes\r\n")); 131 | // lte.getOperators takes in a operator_stats struct pointer and max number of 132 | // structs to scan for, then fills up those objects with operator names and numbers 133 | opsAvailable = lte.getOperators(ops, MAX_OPERATORS); // This will block for up to 3 minutes 134 | 135 | if (opsAvailable > 0) { 136 | // Pretty-print operators we found: 137 | SerialMonitor.println("Found " + String(opsAvailable) + " operators:"); 138 | printOperators(ops, opsAvailable); 139 | 140 | // Wait until the user presses a key to initiate an operator connection 141 | SerialMonitor.println("Press 1-" + String(opsAvailable) + " to select an operator."); 142 | char c = 0; 143 | bool selected = false; 144 | while (!selected) { 145 | while (!SerialMonitor.available()) ; 146 | c = SerialMonitor.read(); 147 | int selection = c - '0'; 148 | if ((selection >= 1) && (selection <= opsAvailable)) { 149 | selected = true; 150 | SerialMonitor.println("Connecting to option " + String(selection)); 151 | if (lte.registerOperator(ops[selection - 1]) == LTE_SHIELD_SUCCESS) { 152 | SerialMonitor.println("Network " + ops[selection - 1].longOp + " registered\r\n"); 153 | } else { 154 | SerialMonitor.println(F("Error connecting to operator. Reset and try again, or try another network.")); 155 | } 156 | } 157 | } 158 | } else { 159 | SerialMonitor.println(F("Did not find an operator. Double-check SIM and antenna, reset and try again, or try another network.")); 160 | while (1) ; 161 | } 162 | } 163 | 164 | // At the very end print connection information 165 | printInfo(); 166 | } 167 | 168 | void loop() { 169 | // Loop won't do much besides provide a debugging interface. 170 | // Pass serial data from Arduino to shield and vice-versa 171 | #ifdef DEBUG_PASSTHROUGH_ENABLED 172 | if (LTEShieldSerial.available()) { 173 | SerialMonitor.write((char) LTEShieldSerial.read()); 174 | } 175 | if (SerialMonitor.available()) { 176 | LTEShieldSerial.write((char) SerialMonitor.read()); 177 | } 178 | #endif 179 | } 180 | 181 | void printInfo(void) { 182 | String currentApn = ""; 183 | IPAddress ip(0, 0, 0, 0); 184 | String currentOperator = ""; 185 | 186 | SerialMonitor.println(F("Connection info:")); 187 | // APN Connection info: APN name and IP 188 | if (lte.getAPN(¤tApn, &ip) == LTE_SHIELD_SUCCESS) { 189 | SerialMonitor.println("APN: " + String(currentApn)); 190 | SerialMonitor.print("IP: "); 191 | SerialMonitor.println(ip); 192 | } 193 | 194 | // Operator name or number 195 | if (lte.getOperator(¤tOperator) == LTE_SHIELD_SUCCESS) { 196 | SerialMonitor.print(F("Operator: ")); 197 | SerialMonitor.println(currentOperator); 198 | } 199 | 200 | // Received signal strength 201 | SerialMonitor.println("RSSI: " + String(lte.rssi())); 202 | SerialMonitor.println(); 203 | } 204 | 205 | void printOperators(struct operator_stats * ops, int operatorsAvailable) { 206 | for (int i = 0; i < operatorsAvailable; i++) { 207 | SerialMonitor.print(String(i + 1) + ": "); 208 | SerialMonitor.print(ops[i].longOp + " (" + String(ops[i].numOp) + ") - "); 209 | switch (ops[i].stat) { 210 | case 0: 211 | SerialMonitor.println(F("UNKNOWN")); 212 | break; 213 | case 1: 214 | SerialMonitor.println(F("AVAILABLE")); 215 | break; 216 | case 2: 217 | SerialMonitor.println(F("CURRENT")); 218 | break; 219 | case 3: 220 | SerialMonitor.println(F("FORBIDDEN")); 221 | break; 222 | } 223 | } 224 | SerialMonitor.println(); 225 | } 226 | 227 | void serialWait() { 228 | while (!SerialMonitor.available()) ; 229 | while (SerialMonitor.available()) SerialMonitor.read(); 230 | } -------------------------------------------------------------------------------- /examples/01_SMS_Send/01_SMS_Send.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Send an SMS with the SparkFun LTE Cat M1/NB-IoT Shield 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 23, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to send an SMS message with the LTE Shield. 12 | 13 | Before beginning, you should have your shield connected on a MNO. 14 | See example 00 for help with that. 15 | 16 | Before uploading, set the DESTINATION_NUMBER constant to the 17 | phone number you want to send a text message to. 18 | (Don't forget to add an internation code (e.g. 1 for US)). 19 | 20 | Once programmed, open the serial monitor, set the baud rate to 9600, 21 | and type a message to be sent via SMS. 22 | 23 | Hardware Connections: 24 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 25 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 26 | the "ARDUINO" position. 27 | */ 28 | 29 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 30 | #include 31 | 32 | // Create a SoftwareSerial object to pass to the LTE_Shield library 33 | SoftwareSerial lteSerial(8, 9); 34 | // Create a LTE_Shield object to use throughout the sketch 35 | LTE_Shield lte; 36 | 37 | // Set the cell phone number to be texted 38 | String DESTINATION_NUMBER = "11234567890"; 39 | 40 | void setup() { 41 | Serial.begin(9600); 42 | 43 | if ( lte.begin(lteSerial, 9600) ) { 44 | Serial.println(F("LTE Shield connected!")); 45 | } 46 | Serial.println(F("Type a message. Send a Newline (\\n) to send it...")); 47 | } 48 | 49 | void loop() { 50 | static String message = ""; 51 | if (Serial.available()) 52 | { 53 | char c = Serial.read(); 54 | // Read a message until a \n (newline) is received 55 | if (c == '\n') { 56 | // Once we receive a newline. send the text. 57 | Serial.println("Sending: \"" + String(message) + "\" to " + 58 | DESTINATION_NUMBER); 59 | // Call lte.sendSMS(String number, String message) to send an SMS 60 | // message. 61 | lte.sendSMS(DESTINATION_NUMBER, message); 62 | message = ""; // Clear message string 63 | } else { 64 | message += c; // Add last character to message 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /examples/02_TCP_Send_Hologram/02_TCP_Send_Hologram.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Send a TCP message to Hologram 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 23, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to send TCP messages to a Hologram server 12 | 13 | Before beginning, you should have your shield connected on a MNO. 14 | See example 00 for help with that. 15 | 16 | Before uploading, set your HOLOGRAM_DEVICE_KEY. This string can be found 17 | in your device's Hologram dashboard. 18 | 19 | Once programmed, open the serial monitor, set the baud rate to 9600, 20 | and type a message to be sent via TCP to the Hologram message service. 21 | Make sure your serial monitor's end-of-line setting is set to "newline". 22 | 23 | Hardware Connections: 24 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 25 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 26 | the "ARDUINO" position. 27 | */ 28 | 29 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 30 | #include 31 | 32 | // Create a SoftwareSerial object to pass to the LTE_Shield library 33 | SoftwareSerial lteSerial(8, 9); 34 | // Create a LTE_Shield object to use throughout the sketch 35 | LTE_Shield lte; 36 | 37 | // Plug in your Hologram device key here: 38 | String HOLOGRAM_DEVICE_KEY = "Ab12CdE4"; 39 | 40 | // These values should remain the same: 41 | const char HOLOGRAM_URL[] = "cloudsocket.hologram.io"; 42 | const unsigned int HOLOGRAM_PORT = 9999; 43 | 44 | void setup() { 45 | Serial.begin(9600); 46 | 47 | if ( lte.begin(lteSerial, 9600) ) { 48 | Serial.println(F("LTE Shield connected!")); 49 | } 50 | 51 | Serial.println(F("Type a message. Send a Newline (\\n) to send it...")); 52 | } 53 | 54 | void loop() { 55 | static String message = ""; 56 | if (Serial.available()) 57 | { 58 | char c = Serial.read(); 59 | // Read a message until a \n (newline) is received 60 | if (c == '\n') { 61 | // Once we receive a newline. send the text. 62 | Serial.println("Sending: " + String(message)); 63 | // Call lte.sendSMS(String number, String message) to send an SMS 64 | // message. 65 | sendHologramMessage(message); 66 | message = ""; // Clear message string 67 | } else { 68 | message += c; // Add last character to message 69 | } 70 | } 71 | lte.poll(); 72 | } 73 | 74 | void sendHologramMessage(String message) 75 | { 76 | int socket = -1; 77 | String hologramMessage; 78 | 79 | // New lines are not handled well 80 | message.replace('\r', ' '); 81 | message.replace('\n', ' '); 82 | 83 | // Construct a JSON-encoded Hologram message string: 84 | hologramMessage = "{\"k\":\"" + HOLOGRAM_DEVICE_KEY + "\",\"d\":\"" + 85 | message + "\"}"; 86 | 87 | // Open a socket 88 | socket = lte.socketOpen(LTE_SHIELD_TCP); 89 | // On success, socketOpen will return a value between 0-5. On fail -1. 90 | if (socket >= 0) { 91 | // Use the socket to connec to the Hologram server 92 | Serial.println("Connecting to socket: " + String(socket)); 93 | if (lte.socketConnect(socket, HOLOGRAM_URL, HOLOGRAM_PORT) == LTE_SHIELD_SUCCESS) { 94 | // Send our message to the server: 95 | Serial.println("Sending: " + String(hologramMessage)); 96 | if (lte.socketWrite(socket, hologramMessage) == LTE_SHIELD_SUCCESS) 97 | { 98 | // On succesful write, close the socket. 99 | if (lte.socketClose(socket) == LTE_SHIELD_SUCCESS) { 100 | Serial.println("Socket " + String(socket) + " closed"); 101 | } 102 | } else { 103 | Serial.println(F("Failed to write")); 104 | } 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /examples/03_TCP_Receive_Hologram/03_TCP_Receive_Hologram.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Receive a TCP message from Hologram server 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 23, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to to sset your shield/Arduino up as a 12 | TCP server and receive a message from a Hologram server. 13 | 14 | Before beginning, you should have your shield connected on a MNO. 15 | See example 00 for help with that. 16 | 17 | Once programmed, open the serial monitor, set the baud rate to 9600. 18 | Use the Hologram dashboard to send a message (via Cloud data) to your device. 19 | You should see the message relayed to your serial monitor. 20 | Make sure the port you're sending to matches HOLOGRAM_LISTEN_PORT. 21 | 22 | Hardware Connections: 23 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 24 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 25 | the "ARDUINO" position. 26 | */ 27 | 28 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 29 | #include 30 | 31 | // Create a SoftwareSerial object to pass to the LTE_Shield library 32 | SoftwareSerial lteSerial(8, 9); 33 | // Create a LTE_Shield object to use throughout the sketch 34 | LTE_Shield lte; 35 | 36 | // Hologram server constants, these shouldn't change: 37 | const unsigned int HOLOGRAM_PORT = 9999; 38 | const unsigned int HOLOGRAM_LISTEN_PORT = 4010; 39 | 40 | int listeningSocket = -1; 41 | 42 | // Callback to process data coming into the LTE module 43 | void processSocketRead(int socket, String response) { 44 | // Print message received, and the IP address it was received from. 45 | // Also print socket received on. 46 | Serial.println("Read: " + response); 47 | Serial.println("Socket: " + String(socket)); 48 | Serial.print("Remote IP: "); 49 | Serial.println(lte.lastRemoteIP()); 50 | } 51 | 52 | // Callback to process when a socket closes 53 | void processSocketClose(int socket) { 54 | // If the closed socket is the one we're listening on. 55 | // Set a flag to re-open the listening socket. 56 | if (socket == listeningSocket) { 57 | listeningSocket = -1; 58 | } else { 59 | // Otherwise print the closed socket 60 | Serial.println("Socket " + String(socket) + " closed"); 61 | } 62 | } 63 | 64 | void setup() { 65 | Serial.begin(9600); 66 | 67 | if ( lte.begin(lteSerial, 9600) ) { 68 | Serial.println(F("LTE Shield connected!")); 69 | } 70 | 71 | lte.setSocketReadCallback(&processSocketRead); 72 | lte.setSocketCloseCallback(&processSocketClose); 73 | } 74 | 75 | void loop() { 76 | lte.poll(); 77 | 78 | // If a listening socket is not open. Set up a new one. 79 | if (listeningSocket < 0) { 80 | listenHologramMessage(); 81 | } 82 | } 83 | 84 | void listenHologramMessage() 85 | { 86 | int sock = -1; 87 | LTE_Shield_error_t err; 88 | 89 | // Open a new available socket 90 | listeningSocket = lte.socketOpen(LTE_SHIELD_TCP); 91 | // If a socket is available it should return a value between 0-5 92 | if (listeningSocket >= 0) { 93 | // Listen on the socket on the defined port 94 | err = lte.socketListen(listeningSocket, HOLOGRAM_LISTEN_PORT); 95 | if (err == LTE_SHIELD_ERROR_SUCCESS) { 96 | Serial.print(F("Listening socket open: ")); 97 | Serial.println(listeningSocket); 98 | } 99 | else { 100 | Serial.println("Unable to listen on socket"); 101 | } 102 | } 103 | else { 104 | Serial.println("Unable to open socket"); 105 | } 106 | } -------------------------------------------------------------------------------- /examples/04_Hologram_Data_Feed/04_Hologram_Data_Feed.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Receive a message from Hologram, then send data on command 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 23, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example combines a bit of example 2 (TCP Send to Hologram) and 12 | example 3 (TCP receive from Hologram). On a specific message receipt from 13 | Hologram (read_analog), this sketch will send a JSON-encoded list of 14 | all six analog measurements. 15 | 16 | After uploading the code, open your Hologram dashboard, select your 17 | device and send a message matching "read_analog" to the device. 18 | 19 | Shortly after this the sketch should respond with a JSON-encoded list 20 | of all six analog measurements. This JSON string can be used for Hologram 21 | routes to send emails, text messages, or more. (See the LTE Shield hookup 22 | guide for more information.) 23 | 24 | Hardware Connections: 25 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 26 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 27 | the "ARDUINO" position. 28 | 29 | Hardware mofification required!: Note that the AREF pin on v1.0 of 30 | the SparkFun LTE Shield is connected to ground. This bug will prevent 31 | accurate readings of the analog pins. We recommend cutting this 32 | pin on the 10-pin Arduino header (effectively disconnecting the shield's 33 | AREF pin from the Arduino). 34 | */ 35 | 36 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 37 | #include 38 | 39 | // Create a SoftwareSerial object to pass to the LTE_Shield library 40 | SoftwareSerial lteSerial(8, 9); 41 | // Create a LTE_Shield object to use throughout the sketch 42 | LTE_Shield lte; 43 | 44 | // Hologram device key. Used to send messages: 45 | String HOLOGRAM_DEVICE_KEY = "Ab12CdE4"; 46 | // Hologram message topic(s): 47 | String HOLOGRAM_ANALOG_TOPIC = "ANALOG"; 48 | 49 | // Hologram Server constants. Shouldn't have to change: 50 | const char HOLOGRAM_URL[] = "cloudsocket.hologram.io"; 51 | const unsigned int HOLOGRAM_PORT = 9999; 52 | const unsigned int HOLOGRAM_LISTEN_PORT = 4010; 53 | 54 | // Pair analog pins up with a JSON identifier string 55 | #define ANALOG_PINS_TO_READ 6 56 | int readPins[ANALOG_PINS_TO_READ] = {A0, A1, A2, A3, A4, A5}; 57 | String pinNames[ANALOG_PINS_TO_READ] = {"A0", "A1", "A2", "A3", "A4", "A5"}; 58 | 59 | // loop flags to check: 60 | boolean doSendAnalog = false; // Send analog values 61 | boolean doServerListen = true; // Open listening server 62 | int listenSocket = -1; // Listen socket -1 is incactive, 0-5 for active socket 63 | 64 | // Callback to process a data read from a socket 65 | void processSocketRead(int socket, String response) { 66 | // Look for the specified string 67 | if (response == "read_analog") { 68 | doSendAnalog = true; // If found set a flag to send analog values 69 | } else { 70 | Serial.println("Server read: " + String(response)); 71 | } 72 | } 73 | 74 | // Callback to process a closed socket 75 | void processSocketClose(int socket) { 76 | Serial.println("Socket " + String(socket) + " closed"); 77 | // If the socket was our listening socket, trigger flag to re-open 78 | if (socket == listenSocket) { 79 | doServerListen = true; 80 | } 81 | } 82 | 83 | void setup() { 84 | Serial.begin(9600); 85 | 86 | for (int i=0; i= 0) { 129 | // Listen on the socket on the defined port 130 | err = lte.socketListen(sock, HOLOGRAM_LISTEN_PORT); 131 | if (err == LTE_SHIELD_ERROR_SUCCESS) { 132 | Serial.print(F("Listening socket open: ")); 133 | Serial.println(sock); 134 | } 135 | else { 136 | Serial.println(F("Unable to listen on socket")); 137 | } 138 | } 139 | else { 140 | Serial.println(F("Unable to open socket")); 141 | } 142 | } 143 | 144 | // Compile analog reads into a JSON-encoded string, then send to Hologram 145 | void sendAnalogValues(void) { 146 | String toSend = "{"; 147 | for (int i = 0; i < ANALOG_PINS_TO_READ; i++) { 148 | toSend += "\\\"" + pinNames[i] + "\\\": "; 149 | toSend += String(analogRead(readPins[i])); 150 | if (i < 5) toSend += ", "; 151 | } 152 | toSend += "}"; 153 | sendHologramMessage(toSend); 154 | } 155 | 156 | void sendHologramMessage(String message) { 157 | int socket = -1; 158 | String hologramMessage; 159 | 160 | hologramMessage = "{\"k\":\"" + HOLOGRAM_DEVICE_KEY + "\",\"d\":\"" + 161 | message + "\",\"t\":[\"" + HOLOGRAM_ANALOG_TOPIC + "\"]}"; 162 | 163 | socket = lte.socketOpen(LTE_SHIELD_TCP); 164 | if (socket >= 0) { 165 | Serial.println("Connecting to socket: " + String(socket)); 166 | if (lte.socketConnect(socket, HOLOGRAM_URL, HOLOGRAM_PORT) == LTE_SHIELD_ERROR_SUCCESS) { 167 | Serial.println(F("Connected to Hologram.io")); 168 | Serial.println("Sending: " + hologramMessage); 169 | if (lte.socketWrite(socket, hologramMessage) == LTE_SHIELD_ERROR_SUCCESS) 170 | { 171 | lte.socketClose(socket); 172 | } 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /examples/05_GPS_Request/05_GPS_Request.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Use the GPS Request feature to request GPS data and receive it in a callback 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: November 1, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to use the gpsRequest feature 12 | 13 | Before beginning, you should have your shield connected to a supported u-blox 14 | GPS module via the I2C (DDC) port. 15 | Supported GPS modules include: 16 | https://www.sparkfun.com/products/15005 17 | 18 | Once programmed, open the serial monitor, set the baud rate to 9600, 19 | and hit enter to watch GPS data begin to stream by. 20 | 21 | Hardware Connections: 22 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 23 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 24 | the "ARDUINO" position. 25 | */ 26 | 27 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 28 | #include 29 | 30 | // Create a SoftwareSerial object to pass to the LTE_Shield library 31 | SoftwareSerial lteSerial(8, 9); 32 | // Create a LTE_Shield object to use throughout the sketch 33 | LTE_Shield lte; 34 | 35 | boolean requestingGPS = false; 36 | unsigned long lastRequest = 0; 37 | #define MIN_REQUEST_INTERVAL 60000 // How often we'll get GPS in loop (in ms) 38 | 39 | #define GPS_REQUEST_TIMEOUT 30 // Time to turn on GPS module and get a fix (in s) 40 | #define GPS_REQUEST_ACCURACY 1 // Desired accuracy from GPS module (in meters) 41 | 42 | // processGpsRead is provided to the LTE_Shield library via a 43 | // callback setter -- setGpsReadCallback. (See end of setup()) 44 | void processGpsRead(ClockData clck, PositionData gps, 45 | SpeedData spd, unsigned long uncertainty) { 46 | 47 | Serial.println(); 48 | Serial.println(); 49 | Serial.println(F("GPS Data Received")); 50 | Serial.println(F("=================")); 51 | Serial.println("Date: " + String(clck.date.month) + "/" + 52 | String(clck.date.day) + "/" + String(clck.date.year)); 53 | Serial.println("Time: " + String(clck.time.hour) + ":" + 54 | String(clck.time.minute) + ":" + String(clck.time.second) + "." + String(clck.time.ms)); 55 | Serial.println("Lat/Lon: " + String(gps.lat, 7) + "/" + String(gps.lon, 7)); 56 | Serial.println("Alt: " + String(gps.alt)); 57 | Serial.println("Uncertainty: " + String(uncertainty)); 58 | Serial.println("Speed: " + String(spd.speed) + " @ " + String(spd.track)); 59 | Serial.println(); 60 | 61 | requestingGPS = false; 62 | } 63 | 64 | void setup() { 65 | Serial.begin(9600); 66 | 67 | // Wait for user to press key in terminal to begin 68 | Serial.println("Press any key to begin GPS'ing"); 69 | while (!Serial.available()) ; 70 | while (Serial.available()) Serial.read(); 71 | 72 | // Initialize the LTE Shield 73 | if ( lte.begin(lteSerial, 9600) ) { 74 | Serial.println(F("LTE Shield connected!")); 75 | } 76 | // Set a callback to return GPS data once requested 77 | lte.setGpsReadCallback(&processGpsRead); 78 | } 79 | 80 | void loop() { 81 | // Poll as often as possible 82 | lte.poll(); 83 | 84 | if (!requestingGPS) { 85 | if ((lastRequest == 0) || (lastRequest + MIN_REQUEST_INTERVAL < millis())) { 86 | Serial.println(F("Requesting GPS data...this can take up to 10 seconds")); 87 | if (lte.gpsRequest(GPS_REQUEST_TIMEOUT, GPS_REQUEST_ACCURACY) == LTE_SHIELD_SUCCESS) { 88 | Serial.println(F("GPS data requested.")); 89 | Serial.println("Wait up to " + String(GPS_REQUEST_TIMEOUT) + " seconds"); 90 | requestingGPS = true; 91 | lastRequest = millis(); 92 | } else { 93 | Serial.println(F("Error requesting GPS")); 94 | } 95 | } 96 | } else { 97 | // Print a '.' every ~1 second if requesting GPS data 98 | // (Hopefully this doesn't mess with poll too much) 99 | if ((millis() % 1000) == 0) { 100 | Serial.print('.'); 101 | delay(1); 102 | } 103 | } 104 | 105 | 106 | } -------------------------------------------------------------------------------- /examples/06_GPS_GPRMS/06_GPS_GPRMS.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Use the GPS RMC sentence read feature to get position, speed, and clock data 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: November 2, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to use the gpsGetRmc feature. 12 | 13 | Before beginning, you should have your shield connected to a supported u-blox 14 | GPS module via the I2C (DDC) port. 15 | Supported GPS modules include: 16 | https://www.sparkfun.com/products/15005 17 | 18 | Once programmed, open the serial monitor, set the baud rate to 9600, 19 | and hit enter to watch GPS data begin to stream by. 20 | 21 | Hardware Connections: 22 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 23 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 24 | the "ARDUINO" gpsition. 25 | */ 26 | 27 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 28 | #include 29 | 30 | // Create a SoftwareSerial object to pass to the LTE_Shield library 31 | SoftwareSerial lteSerial(8, 9); 32 | // Create a LTE_Shield object to use throughout the sketch 33 | LTE_Shield lte; 34 | 35 | PositionData gps; 36 | SpeedData spd; 37 | ClockData clk; 38 | boolean valid; 39 | 40 | #define GPS_POLL_RATE 5000 // Read GPS every 2 seconds 41 | unsigned long lastGpsPoll = 0; 42 | 43 | void setup() { 44 | Serial.begin(9600); 45 | 46 | // Wait for user to press key in terminal to begin 47 | Serial.println("Press any key to begin GPS'ing"); 48 | while (!Serial.available()) ; 49 | while (Serial.available()) Serial.read(); 50 | 51 | // Initialize the LTE Shield 52 | if ( lte.begin(lteSerial, 9600) ) { 53 | Serial.println(F("LTE Shield connected!")); 54 | } 55 | 56 | // Enable the GPS's RMC sentence output. This will also turn the 57 | // GPS module on (lte.gpsPower(true)) if it's not already 58 | if (lte.gpsEnableRmc(true) != LTE_SHIELD_SUCCESS) { 59 | Serial.println(F("Error initializing GPS.")); 60 | while (1) ; 61 | } 62 | } 63 | 64 | void loop() { 65 | if ((lastGpsPoll == 0) || (lastGpsPoll + GPS_POLL_RATE < millis())) { 66 | // Call lte.gpsGetRmc to get coordinate, speed, and timing data 67 | // from the GPS module. Valid can be used to check if the GPS is 68 | // reporting valid data 69 | if (lte.gpsGetRmc(&gps, &spd, &clk, &valid) == LTE_SHIELD_SUCCESS) { 70 | printGPS(); 71 | lastGpsPoll = millis(); 72 | } else { 73 | delay(1000); // If RMC read fails, wait a second and try again 74 | } 75 | } 76 | } 77 | 78 | void printGPS(void) { 79 | Serial.println(); 80 | Serial.println("UTC: " + String(gps.utc)); 81 | Serial.print("Time: "); 82 | if (clk.time.hour < 10) Serial.print('0'); // Print leading 0 83 | Serial.print(String(clk.time.hour) + ":"); 84 | if (clk.time.minute < 10) Serial.print('0'); // Print leading 0 85 | Serial.print(String(clk.time.minute) + ":"); 86 | if (clk.time.second < 10) Serial.print('0'); // Print leading 0 87 | Serial.println(clk.time.second); 88 | Serial.println("Latitude: " + String(gps.lat, 7) + " " + String(gps.latDir)); 89 | Serial.println("Longitude: " + String(gps.lon, 7) + " " + String(gps.lonDir)); 90 | Serial.println("Speed: " + String(spd.speed, 4) + " @ " + String(spd.track, 4)); 91 | Serial.println("Date: " + String(clk.date.month) + "/" + 92 | String(clk.date.day) + "/" + String(clk.date.year)); 93 | Serial.println("Magnetic variation: " + String(spd.magVar) + " " + spd.magVarDir); 94 | Serial.println("Status: " + String(gps.status)); 95 | Serial.println("Mode: " + String(gps.mode)); 96 | Serial.println(); 97 | } -------------------------------------------------------------------------------- /examples/Network_Info/Network_Info.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Register your LTE Shield/SIM combo on a mobile network operator 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 23, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example demonstrates how to initialize your Cat M1/NB-IoT shield, and 12 | connect it to a mobile network operator (Verizon, AT&T, T-Mobile, etc.). 13 | 14 | Before beginning, you may need to adjust the mobile network operator (MNO) 15 | setting on line 83. See comments above that line to help select either 16 | Verizon, T-Mobile, AT&T or others. 17 | 18 | Hardware Connections: 19 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 20 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 21 | the "ARDUINO" position. 22 | */ 23 | 24 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 25 | #include 26 | 27 | // We need to pass a Serial or SoftwareSerial object to the LTE Shield 28 | // library. Below creates a SoftwareSerial object on the standard LTE 29 | // Shield RX/TX pins: 30 | // Note: if you're using an Arduino board with a dedicated hardware 31 | // serial port, comment out the line below. (Also see note in setup.) 32 | SoftwareSerial lteSerial(8, 9); 33 | 34 | // Create a LTE_Shield object to be used throughout the sketch: 35 | LTE_Shield lte; 36 | 37 | // Map registration status messages to more readable strings 38 | String registrationString[] = { 39 | "Not registered", // 0 40 | "Registered, home", // 1 41 | "Searching for operator", // 2 42 | "Registration denied", // 3 43 | "Registration unknown", // 4 44 | "Registered, roaming", // 5 45 | "Registered, home (SMS only)", // 6 46 | "Registered, roaming (SMS only)", // 7 47 | "Registered, home, CSFB not preferred", // 8 48 | "Registered, roaming, CSFB not prefered" // 9 49 | }; 50 | 51 | // Network operator can be set to either: 52 | // MNO_SW_DEFAULT -- DEFAULT 53 | // MNO_ATT -- AT&T 54 | // MNO_VERIZON -- Verizon 55 | // MNO_TELSTRA -- Telstra 56 | // MNO_TMO -- T-Mobile 57 | const mobile_network_operator_t MOBILE_NETWORK_OPERATOR = MNO_VERIZON; 58 | 59 | // APN -- Access Point Name. Gateway between GPRS MNO 60 | // and another computer network. E.g. "hologram 61 | const String APN = "hologram"; 62 | 63 | void setup() { 64 | Serial.begin(9600); 65 | 66 | Serial.println(F("Initializing the LTE Shield...")); 67 | Serial.println(F("...this may take ~25 seconds if the shield is off.")); 68 | Serial.println(F("...it may take ~5 seconds if it just turned on.")); 69 | 70 | // Call lte.begin and pass it your Serial/SoftwareSerial object to 71 | // communicate with the LTE Shield. 72 | // Note: If you're using an Arduino with a dedicated hardware serial 73 | // poert, you may instead slide "Serial" into this begin call. 74 | 75 | if ( lte.begin(lteSerial) ) { 76 | Serial.println(F("LTE Shield connected!")); 77 | } else { 78 | Serial.println(F("Unable to communicate with the shield.")); 79 | Serial.println(F("Make sure the serial switch is in the correct position.")); 80 | Serial.println(F("Manually power-on (hold POWER for 3 seconds) on and try again.")); 81 | while (1) ; // Loop forever on fail 82 | } 83 | Serial.println(); 84 | 85 | if (!lte.setNetwork(MOBILE_NETWORK_OPERATOR)) { 86 | Serial.println(F("Error setting network. Try cycling power on your Arduino/shield.")); 87 | while (1) ; 88 | } 89 | if (lte.setAPN(APN) == LTE_SHIELD_SUCCESS) { 90 | Serial.println(F("APN successfully set.")); 91 | } 92 | Serial.println(F("Network set. Ready to go!")); 93 | 94 | // RSSI: Received signal strength: 95 | Serial.println("RSSI: " + String(lte.rssi())); 96 | // Registration Status 97 | int regStatus = lte.registration(); 98 | if ((regStatus >= 0) && (regStatus <= 9)) { 99 | Serial.println("Network registration: " + registrationString[regStatus]); 100 | } 101 | if (regStatus > 0) { 102 | Serial.println(F("All set. Go to the next example!")); 103 | } 104 | } 105 | 106 | void loop() { 107 | // Do nothing. Now that we're registered move on to the next example. 108 | } -------------------------------------------------------------------------------- /examples/Serial_Passthrough/Serial_Passthrough.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Send AT commands to the SARA-R4 via the Serial Port 3 | By: Jim Lindblom 4 | SparkFun Electronics 5 | Date: October 26, 2018 6 | License: This code is public domain but you buy me a beer if you use this 7 | and we meet someday (Beerware license). 8 | Feel like supporting our work? Buy a board from SparkFun! 9 | https://www.sparkfun.com/products/14997 10 | 11 | This example sketch provides a direct interface to the SARA-R4 module's 12 | AT command port. It will initialize the device, and then let you run free! 13 | Consult the SARA-R4 AT command set for a list of commands. 14 | 15 | After uploading the code, open your Serial Monitor, set the baud rate to 16 | 9600 baud. We also recommend setting the line-ending setting to 17 | "Carriage Return", so your AT commands will be read in by the SARA module. 18 | 19 | Hardware Connections: 20 | Attach the SparkFun LTE Cat M1/NB-IoT Shield to your Arduino 21 | Power the shield with your Arduino -- ensure the PWR_SEL switch is in 22 | the "ARDUINO" position. 23 | */ 24 | 25 | //Click here to get the library: http://librarymanager/All#SparkFun_LTE_Shield_Arduino_Library 26 | #include 27 | 28 | // Create a SoftwareSerial object to pass to the LTE_Shield library 29 | SoftwareSerial lteSerial(8, 9); 30 | // Create a LTE_Shield object to use throughout the sketch 31 | LTE_Shield lte; 32 | 33 | void setup() { 34 | Serial.begin(9600); 35 | 36 | if ( lte.begin(lteSerial, 9600) ) { 37 | Serial.println(F("LTE Shield connected!")); 38 | } 39 | Serial.println(F("Ready to passthrough!\r\n")); 40 | } 41 | 42 | void loop() { 43 | if (Serial.available()) { 44 | lteSerial.write((char) Serial.read()); 45 | } 46 | if (lteSerial.available()) { 47 | Serial.write((char) lteSerial.read()); 48 | } 49 | } -------------------------------------------------------------------------------- /keywords.txt: -------------------------------------------------------------------------------- 1 | ####################################### 2 | # Syntax Coloring Map 3 | ####################################### 4 | 5 | ####################################### 6 | # Datatypes KEYWORD1 7 | ####################################### 8 | 9 | SparkFun_LTE_Shield_Arduino_Library KEYWORD1 10 | LTE_Shield KEYWORD1 11 | mobile_network_operator_t KEYWORD1 12 | LTE_Shield_error_t KEYWORD1 13 | LTE_Shield_registration_status_t KEYWORD1 14 | DateData KEYWORD1 15 | TimeData KEYWORD1 16 | ClockData KEYWORD1 17 | PositionData KEYWORD1 18 | SpeedData KEYWORD1 19 | operator_stats KEYWORD1 20 | lte_shield_socket_protocol_t KEYWORD1 21 | lte_shield_message_format_t KEYWORD1 22 | 23 | ####################################### 24 | # Methods and Functions KEYWORD2 25 | ####################################### 26 | 27 | begin KEYWORD2 28 | day KEYWORD2 29 | month KEYWORD2 30 | year KEYWORD2 31 | hour KEYWORD2 32 | minute KEYWORD2 33 | second KEYWORD2 34 | ms KEYWORD2 35 | tzh KEYWORD2 36 | tzm KEYWORD2 37 | date KEYWORD2 38 | time KEYWORD2 39 | utc KEYWORD2 40 | lat KEYWORD2 41 | latDir KEYWORD2 42 | lon KEYWORD2 43 | lonDir KEYWORD2 44 | alt KEYWORD2 45 | mode KEYWORD2 46 | status KEYWORD2 47 | speed KEYWORD2 48 | track KEYWORD2 49 | magVar KEYWORD2 50 | magVarDir KEYWORD2 51 | stat KEYWORD2 52 | shortOp KEYWORD2 53 | longOp KEYWORD2 54 | numOp KEYWORD2 55 | act KEYWORD2 56 | begin KEYWORD2 57 | poll KEYWORD2 58 | setSocketReadCallback KEYWORD2 59 | setSocketCloseCallback KEYWORD2 60 | setGpsReadCallback KEYWORD2 61 | write KEYWORD2 62 | at KEYWORD2 63 | enableEcho KEYWORD2 64 | imei KEYWORD2 65 | imsi KEYWORD2 66 | ccid KEYWORD2 67 | reset KEYWORD2 68 | clock KEYWORD2 69 | autoTimeZone KEYWORD2 70 | rssi KEYWORD2 71 | registration KEYWORD2 72 | setNetwork KEYWORD2 73 | getNetwork KEYWORD2 74 | setAPN KEYWORD2 75 | getAPN KEYWORD2 76 | enterPPP KEYWORD2 77 | getOperators KEYWORD2 78 | registerOperator KEYWORD2 79 | getOperator KEYWORD2 80 | deregisterOperator KEYWORD2 81 | setSMSMessageFormat KEYWORD2 82 | sendSMS KEYWORD2 83 | setBaud KEYWORD2 84 | setGpioMode KEYWORD2 85 | getGpioMode KEYWORD2 86 | socketOpen KEYWORD2 87 | socketClose KEYWORD2 88 | socketConnect KEYWORD2 89 | socketWrite KEYWORD2 90 | socketWrite KEYWORD2 91 | socketRead KEYWORD2 92 | socketListen KEYWORD2 93 | IPAddress lastRemoteIP KEYWORD2 94 | boolean gpsOn KEYWORD2 95 | gpsPower KEYWORD2 96 | gpsEnableClock KEYWORD2 97 | gpsGetClock KEYWORD2 98 | gpsEnableFix KEYWORD2 99 | gpsGetFix KEYWORD2 100 | gpsGetFix KEYWORD2 101 | gpsEnablePos KEYWORD2 102 | gpsGetPos KEYWORD2 103 | gpsEnableSat KEYWORD2 104 | gpsGetSat KEYWORD2 105 | gpsEnableRmc KEYWORD2 106 | gpsGetRmc KEYWORD2 107 | gpsEnableSpeed KEYWORD2 108 | gpsGetSpeed KEYWORD2 109 | gpsRequest KEYWORD2 110 | 111 | ####################################### 112 | # Constants LITERAL1 113 | ####################################### 114 | 115 | SARA-R410M-02B LITERAL1 116 | MNO_INVALID LITERAL1 117 | MNO_SW_DEFAULT LITERAL1 118 | MNO_SIM_ICCD LITERAL1 119 | MNO_ATT LITERAL1 120 | MNO_VERIZON LITERAL1 121 | MNO_TELSTRA LITERAL1 122 | MNO_TMO LITERAL1 123 | MNO_CT LITERAL1 124 | LTE_SHIELD_ERROR_INVALID LITERAL1 125 | LTE_SHIELD_ERROR_SUCCESS LITERAL1 126 | LTE_SHIELD_ERROR_OUT_OF_MEMORY LITERAL1 127 | LTE_SHIELD_ERROR_TIMEOUT LITERAL1 128 | LTE_SHIELD_ERROR_UNEXPECTED_PARAM LITERAL1 129 | LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE LITERAL1 130 | LTE_SHIELD_ERROR_NO_RESPONSE LITERAL1 131 | LTE_SHIELD_ERROR_DEREGISTERED LITERAL1 132 | LTE_SHIELD_ERROR_SUCCESS LITERAL1 133 | LTE_SHIELD_REGISTRATION_INVALID LITERAL1 134 | LTE_SHIELD_REGISTRATION_NOT_REGISTERED LITERAL1 135 | LTE_SHIELD_REGISTRATION_HOME LITERAL1 136 | LTE_SHIELD_REGISTRATION_SEARCHING LITERAL1 137 | LTE_SHIELD_REGISTRATION_DENIED LITERAL1 138 | LTE_SHIELD_REGISTRATION_UNKNOWN LITERAL1 139 | LTE_SHIELD_REGISTRATION_ROAMING LITERAL1 140 | LTE_SHIELD_REGISTRATION_HOME_SMS_ONLY LITERAL1 141 | LTE_SHIELD_REGISTRATION_ROAMING_SMS_ONLY LITERAL1 142 | LTE_SHIELD_REGISTRATION_HOME_CSFB_NOT_PREFERRED LITERAL1 143 | LTE_SHIELD_REGISTRATION_ROAMING_CSFB_NOT_PREFERRED LITERAL1 144 | LTE_SHIELD_TCP LITERAL1 145 | LTE_SHIELD_UDP LITERAL1 146 | LTE_SHIELD_MESSAGE_FORMAT_PDU LITERAL1 147 | LTE_SHIELD_MESSAGE_FORMAT_TEXT LITERAL1 148 | GPIO1 LITERAL1 149 | GPIO2 LITERAL1 150 | GPIO3 LITERAL1 151 | GPIO4 LITERAL1 152 | GPIO5 LITERAL1 153 | GPIO6 LITERAL1 154 | GPIO_MODE_INVALID LITERAL1 155 | GPIO_OUTPUT LITERAL1 156 | GPIO_INPUT LITERAL1 157 | NETWORK_STATUS LITERAL1 158 | GNSS_SUPPLY_ENABLE LITERAL1 159 | GNSS_DATA_READY LITERAL1 160 | GNSS_RTC_SHARING LITERAL1 161 | SIM_CARD_DETECTION LITERAL1 162 | HEADSET_DETECTION LITERAL1 163 | GSM_TX_BURST_INDICATION LITERAL1 164 | MODULE_OPERATING_STATUS_INDICATION LITERAL1 165 | MODULE_FUNCTIONALITY_STATUS_INDICATION LITERAL1 166 | I2S_DIGITAL_AUDIO_INTERFACE LITERAL1 167 | SPI_SERIAL_INTERFACE LITERAL1 168 | MASTER_CLOCK_GENRATION LITERAL1 169 | UART_INTERFACE LITERAL1 170 | WIFI_ENABLE LITERAL1 171 | RING_INDICATION LITERAL1 172 | LAST_GASP_ENABLE LITERAL1 173 | PAD_DISABLED LITERAL1 174 | -------------------------------------------------------------------------------- /library.properties: -------------------------------------------------------------------------------- 1 | name=SparkFun LTE Shield Arduino Library 2 | version=1.3.0 3 | author=SparkFun Electronics 4 | maintainer=SparkFun Electronics 5 | sentence=Library for the SparkFun LTE Shield -- based on the u-blox SARA-R410M-02B 6 | paragraph=An Arduino Library for the SparkFun LTE Shield -- based on the u-blox SARA-R410M-02B. 7 | category=Communication 8 | url=https://github.com/sparkfun/SparkFun_LTE_Shield_Arduino_Library 9 | architectures=* 10 | -------------------------------------------------------------------------------- /src/SparkFun_LTE_Shield_Arduino_Library.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino Library for the SparkFun LTE CAT M1/NB-IoT Shield - SARA-R4 3 | 4 | SparkFun sells these at its website: www.sparkfun.com 5 | Do you like this library? Help support SparkFun. Buy a board! 6 | https://www.sparkfun.com/products/14997 7 | Written by Jim Lindblom @ SparkFun Electronics, September 5, 2018 8 | 9 | This Arduino library provides mechanisms to initialize and use 10 | the SARA-R4 module over either a SoftwareSerial or hardware serial port. 11 | 12 | Supported features include: 13 | * Network registration -- Register your shield on a MNO 14 | * SMS messaging -- Send an SMS message 15 | * TCP/IP Messaging -- Sending data to servers or setting the SARA 16 | module up as a listening socket. 17 | * u-blox GPS module support -- Plug in a u-blox GPS module via 18 | I2C to read it's location data. 19 | 20 | Development environment specifics: 21 | Arduino IDE 1.8.5 22 | This program is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | You should have received a copy of the GNU General Public License 27 | along with this program. If not, see . 28 | */ 29 | 30 | #include 31 | 32 | #define LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT 1000 33 | #define LTE_SHIELD_SET_BAUD_TIMEOUT 500 34 | #define LTE_SHIELD_POWER_PULSE_PERIOD 3200 35 | #define LTE_RESET_PULSE_PERIOD 10000 36 | #define LTE_SHIELD_IP_CONNECT_TIMEOUT 60000 37 | #define LTE_SHIELD_POLL_DELAY 1 38 | #define LTE_SHIELD_SOCKET_WRITE_TIMEOUT 10000 39 | 40 | // ## Suported AT Commands 41 | // ### General 42 | const char LTE_SHIELD_COMMAND_AT[] = "AT"; // AT "Test" 43 | const char LTE_SHIELD_COMMAND_ECHO[] = "E"; // Local Echo 44 | const char LTE_SHIELD_COMMAND_IMEI[] = "+CGSN"; // IMEI identification 45 | const char LTE_SHIELD_COMMAND_IMSI[] = "+CIMI"; // IMSI identification 46 | const char LTE_SHIELD_COMMAND_CCID[] = "+CCID"; // SIM CCID 47 | // ### Control and status 48 | const char LTE_SHIELD_COMMAND_FUNC[] = "+CFUN"; // Functionality (reset, etc.) 49 | const char LTE_SHIELD_COMMAND_CLOCK[] = "+CCLK"; // Clock 50 | const char LTE_SHIELD_COMMAND_AUTO_TZ[] = "+CTZU"; // Automatic time zone update 51 | // ### Network service 52 | const char LTE_SHIELD_COMMAND_MNO[] = "+UMNOPROF"; // MNO (mobile network operator) Profile 53 | const char LTE_SHIELD_SIGNAL_QUALITY[] = "+CSQ"; 54 | const char LTE_SHIELD_REGISTRATION_STATUS[] = "+CREG"; 55 | const char LTE_SHIELD_MESSAGE_PDP_DEF[] = "+CGDCONT"; 56 | const char LTE_SHIELD_MESSAGE_ENTER_PPP[] = "D"; 57 | const char LTE_SHIELD_OPERATOR_SELECTION[] = "+COPS"; 58 | // V24 control and V25ter (UART interface) 59 | const char LTE_SHIELD_COMMAND_BAUD[] = "+IPR"; // Baud rate 60 | // ### GPIO 61 | const char LTE_SHIELD_COMMAND_GPIO[] = "+UGPIOC"; // GPIO Configuration 62 | // ### IP 63 | const char LTE_SHIELD_CREATE_SOCKET[] = "+USOCR"; // Create a new socket 64 | const char LTE_SHIELD_CLOSE_SOCKET[] = "+USOCL"; // Close a socket 65 | const char LTE_SHIELD_CONNECT_SOCKET[] = "+USOCO"; // Connect to server on socket 66 | const char LTE_SHIELD_WRITE_SOCKET[] = "+USOWR"; // Write data to a socket 67 | const char LTE_SHIELD_READ_SOCKET[] = "+USORD"; // Read from a socket 68 | const char LTE_SHIELD_LISTEN_SOCKET[] = "+USOLI"; // Listen for connection on socket 69 | // ### SMS 70 | const char LTE_SHIELD_MESSAGE_FORMAT[] = "+CMGF"; // Set SMS message format 71 | const char LTE_SHIELD_SEND_TEXT[] = "+CMGS"; // Send SMS message 72 | // ### GPS 73 | const char LTE_SHIELD_GPS_POWER[] = "+UGPS"; 74 | const char LTE_SHIELD_GPS_REQUEST_LOCATION[] = "+ULOC"; 75 | const char LTE_SHIELD_GPS_GPRMC[] = "+UGRMC"; 76 | 77 | const char LTE_SHIELD_RESPONSE_OK[] = "OK\r\n"; 78 | 79 | // CTRL+Z and ESC ASCII codes for SMS message sends 80 | const char ASCII_CTRL_Z = 0x1A; 81 | const char ASCII_ESC = 0x1B; 82 | 83 | #define NOT_AT_COMMAND false 84 | #define AT_COMMAND true 85 | 86 | #define LTE_SHIELD_NUM_SOCKETS 6 87 | 88 | #define NUM_SUPPORTED_BAUD 6 89 | const unsigned long LTE_SHIELD_SUPPORTED_BAUD[NUM_SUPPORTED_BAUD] = 90 | { 91 | 115200, 92 | 9600, 93 | 19200, 94 | 38400, 95 | 57600, 96 | 230400}; 97 | #define LTE_SHIELD_DEFAULT_BAUD_RATE 115200 98 | 99 | char lteShieldRXBuffer[128]; 100 | 101 | static boolean parseGPRMCString(char *rmcString, PositionData *pos, ClockData *clk, SpeedData *spd); 102 | 103 | LTE_Shield::LTE_Shield(uint8_t powerPin, uint8_t resetPin) 104 | { 105 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 106 | _softSerial = NULL; 107 | #endif 108 | _hardSerial = NULL; 109 | _baud = 0; 110 | _resetPin = resetPin; 111 | _powerPin = powerPin; 112 | _socketReadCallback = NULL; 113 | _socketCloseCallback = NULL; 114 | _lastRemoteIP = {0, 0, 0, 0}; 115 | _lastLocalIP = {0, 0, 0, 0}; 116 | 117 | memset(lteShieldRXBuffer, 0, 128); 118 | } 119 | 120 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 121 | boolean LTE_Shield::begin(SoftwareSerial &softSerial, unsigned long baud) 122 | { 123 | LTE_Shield_error_t err; 124 | 125 | _softSerial = &softSerial; 126 | 127 | err = init(baud); 128 | if (err == LTE_SHIELD_ERROR_SUCCESS) 129 | { 130 | return true; 131 | } 132 | return false; 133 | } 134 | #endif 135 | 136 | boolean LTE_Shield::begin(HardwareSerial &hardSerial, unsigned long baud) 137 | { 138 | LTE_Shield_error_t err; 139 | 140 | _hardSerial = &hardSerial; 141 | 142 | err = init(baud); 143 | if (err == LTE_SHIELD_ERROR_SUCCESS) 144 | { 145 | return true; 146 | } 147 | return false; 148 | } 149 | 150 | boolean LTE_Shield::poll(void) 151 | { 152 | int avail = 0; 153 | char c = 0; 154 | bool handled = false; 155 | 156 | memset(lteShieldRXBuffer, 0, 128); 157 | 158 | if (hwAvailable()) 159 | { 160 | while (c != '\n') 161 | { 162 | if (hwAvailable()) 163 | { 164 | c = readChar(); 165 | lteShieldRXBuffer[avail++] = c; 166 | } 167 | } 168 | { 169 | int socket, length; 170 | if (sscanf(lteShieldRXBuffer, "+UUSORD: %d,%d", &socket, &length) == 2) 171 | { 172 | parseSocketReadIndication(socket, length); 173 | handled = true; 174 | } 175 | } 176 | { 177 | int socket, listenSocket; 178 | unsigned int port, listenPort; 179 | IPAddress remoteIP, localIP; 180 | 181 | if (sscanf(lteShieldRXBuffer, 182 | "+UUSOLI: %d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", 183 | &socket, 184 | &remoteIP[0], &remoteIP[1], &remoteIP[2], &remoteIP[3], 185 | &port, &listenSocket, 186 | &localIP[0], &localIP[1], &localIP[2], &localIP[3], 187 | &listenPort) > 4) 188 | { 189 | parseSocketListenIndication(localIP, remoteIP); 190 | handled = true; 191 | } 192 | } 193 | { 194 | int socket; 195 | 196 | if (sscanf(lteShieldRXBuffer, 197 | "+UUSOCL: %d", &socket) == 1) 198 | { 199 | if ((socket >= 0) && (socket <= 6)) 200 | { 201 | if (_socketCloseCallback != NULL) 202 | { 203 | _socketCloseCallback(socket); 204 | } 205 | } 206 | handled = true; 207 | } 208 | } 209 | { 210 | ClockData clck; 211 | PositionData gps; 212 | SpeedData spd; 213 | unsigned long uncertainty; 214 | int scanNum; 215 | unsigned int latH, lonH, altU, speedU, trackU; 216 | char latL[10], lonL[10]; 217 | 218 | if (strstr(lteShieldRXBuffer, "+UULOC")) 219 | { 220 | // Found a Location string! 221 | scanNum = sscanf(lteShieldRXBuffer, 222 | "+UULOC: %hhu/%hhu/%u,%hhu:%hhu:%hhu.%u,%u.%[^,],%u.%[^,],%u,%lu,%u,%u,*%s", 223 | &clck.date.day, &clck.date.month, &clck.date.year, 224 | &clck.time.hour, &clck.time.minute, &clck.time.second, &clck.time.ms, 225 | &latH, latL, &lonH, lonL, &altU, &uncertainty, 226 | &speedU, &trackU); 227 | if (scanNum < 13) 228 | return false; // Break out if we didn't find enough 229 | 230 | gps.lat = (float)latH + ((float)atol(latL) / pow(10, strlen(latL))); 231 | gps.lon = (float)lonH + ((float)atol(lonL) / pow(10, strlen(lonL))); 232 | gps.alt = (float)altU; 233 | if (scanNum == 15) // If detailed response, get speed data 234 | { 235 | spd.speed = (float)speedU; 236 | spd.track = (float)trackU; 237 | } 238 | 239 | if (_gpsRequestCallback != NULL) 240 | { 241 | _gpsRequestCallback(clck, gps, spd, uncertainty); 242 | } 243 | } 244 | } 245 | 246 | if ((handled == false) && (strlen(lteShieldRXBuffer) > 2)) 247 | { 248 | //Serial.println("Poll: " + String(lteShieldRXBuffer)); 249 | } 250 | else 251 | { 252 | } 253 | } 254 | return handled; 255 | } 256 | 257 | void LTE_Shield::setSocketReadCallback(void (*socketReadCallback)(int, String)) 258 | { 259 | _socketReadCallback = socketReadCallback; 260 | } 261 | 262 | void LTE_Shield::setSocketCloseCallback(void (*socketCloseCallback)(int)) 263 | { 264 | _socketCloseCallback = socketCloseCallback; 265 | } 266 | 267 | void LTE_Shield::setGpsReadCallback(void (*gpsRequestCallback)(ClockData time, 268 | PositionData gps, SpeedData spd, unsigned long uncertainty)) 269 | { 270 | _gpsRequestCallback = gpsRequestCallback; 271 | } 272 | 273 | size_t LTE_Shield::write(uint8_t c) 274 | { 275 | if (_hardSerial != NULL) 276 | { 277 | return _hardSerial->write(c); 278 | } 279 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 280 | else if (_softSerial != NULL) 281 | { 282 | return _softSerial->write(c); 283 | } 284 | #endif 285 | return (size_t)0; 286 | } 287 | 288 | size_t LTE_Shield::write(const char *str) 289 | { 290 | if (_hardSerial != NULL) 291 | { 292 | return _hardSerial->print(str); 293 | } 294 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 295 | else if (_softSerial != NULL) 296 | { 297 | return _softSerial->print(str); 298 | } 299 | #endif 300 | return (size_t)0; 301 | } 302 | 303 | size_t LTE_Shield::write(const char *buffer, size_t size) 304 | { 305 | if (_hardSerial != NULL) 306 | { 307 | return _hardSerial->print(buffer); 308 | } 309 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 310 | else if (_softSerial != NULL) 311 | { 312 | return _softSerial->print(buffer); 313 | } 314 | #endif 315 | return (size_t)0; 316 | } 317 | 318 | LTE_Shield_error_t LTE_Shield::at(void) 319 | { 320 | LTE_Shield_error_t err; 321 | char *command; 322 | 323 | err = sendCommandWithResponse(NULL, LTE_SHIELD_RESPONSE_OK, NULL, 324 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 325 | 326 | return err; 327 | } 328 | 329 | LTE_Shield_error_t LTE_Shield::enableEcho(boolean enable) 330 | { 331 | LTE_Shield_error_t err; 332 | char *command; 333 | 334 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_ECHO) + 2); 335 | if (command == NULL) 336 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 337 | if (enable) 338 | { 339 | sprintf(command, "%s1", LTE_SHIELD_COMMAND_ECHO); 340 | } 341 | else 342 | { 343 | sprintf(command, "%s0", LTE_SHIELD_COMMAND_ECHO); 344 | } 345 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 346 | NULL, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 347 | 348 | free(command); 349 | 350 | return err; 351 | } 352 | 353 | String LTE_Shield::imei(void) 354 | { 355 | char *response; 356 | char imeiResponse[16]; 357 | LTE_Shield_error_t err; 358 | 359 | response = lte_calloc_char(sizeof(imeiResponse) + 16); 360 | 361 | err = sendCommandWithResponse(LTE_SHIELD_COMMAND_IMEI, 362 | LTE_SHIELD_RESPONSE_OK, response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 363 | if (err == LTE_SHIELD_ERROR_SUCCESS) 364 | { 365 | if (sscanf(response, "\r\n%s\r\n", imeiResponse) != 1) 366 | { 367 | memset(imeiResponse, 0, 16); 368 | } 369 | } 370 | free(response); 371 | return String(imeiResponse); 372 | ; 373 | } 374 | 375 | String LTE_Shield::imsi(void) 376 | { 377 | char *response; 378 | char imsiResponse[16]; 379 | LTE_Shield_error_t err; 380 | 381 | response = lte_calloc_char(sizeof(imsiResponse) + 16); 382 | 383 | err = sendCommandWithResponse(LTE_SHIELD_COMMAND_IMSI, 384 | LTE_SHIELD_RESPONSE_OK, response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 385 | if (err == LTE_SHIELD_ERROR_SUCCESS) 386 | { 387 | if (sscanf(response, "\r\n%s\r\n", imsiResponse) != 1) 388 | { 389 | memset(imsiResponse, 0, 16); 390 | } 391 | } 392 | free(response); 393 | return String(imsiResponse); 394 | } 395 | 396 | String LTE_Shield::ccid(void) 397 | { 398 | char *response; 399 | char ccidResponse[21]; 400 | LTE_Shield_error_t err; 401 | 402 | response = lte_calloc_char(sizeof(ccidResponse) + 16); 403 | 404 | err = sendCommandWithResponse(LTE_SHIELD_COMMAND_CCID, 405 | LTE_SHIELD_RESPONSE_OK, response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 406 | if (err == LTE_SHIELD_ERROR_SUCCESS) 407 | { 408 | if (sscanf(response, "\r\n+CCID: %s", ccidResponse) != 1) 409 | { 410 | memset(ccidResponse, 0, 21); 411 | } 412 | } 413 | free(response); 414 | return String(ccidResponse); 415 | } 416 | 417 | LTE_Shield_error_t LTE_Shield::reset(void) 418 | { 419 | LTE_Shield_error_t err; 420 | 421 | err = functionality(SILENT_RESET); 422 | if (err == LTE_SHIELD_ERROR_SUCCESS) 423 | { 424 | // Reset will set the baud rate back to 115200 425 | //beginSerial(9600); 426 | err = LTE_SHIELD_ERROR_INVALID; 427 | while (err != LTE_SHIELD_ERROR_SUCCESS) 428 | { 429 | beginSerial(LTE_SHIELD_DEFAULT_BAUD_RATE); 430 | setBaud(_baud); 431 | delay(200); 432 | beginSerial(_baud); 433 | err = at(); 434 | delay(500); 435 | } 436 | return init(_baud); 437 | } 438 | return err; 439 | } 440 | 441 | String LTE_Shield::clock(void) 442 | { 443 | LTE_Shield_error_t err; 444 | char *command; 445 | char *response; 446 | char *clockBegin; 447 | char *clockEnd; 448 | 449 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_CLOCK) + 2); 450 | if (command == NULL) 451 | return ""; 452 | sprintf(command, "%s?", LTE_SHIELD_COMMAND_CLOCK); 453 | 454 | response = lte_calloc_char(48); 455 | if (response == NULL) 456 | { 457 | free(command); 458 | return ""; 459 | } 460 | 461 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 462 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 463 | if (err != LTE_SHIELD_ERROR_SUCCESS) 464 | { 465 | free(command); 466 | free(response); 467 | return ""; 468 | } 469 | 470 | // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n 471 | clockBegin = strchr(response, '\"'); // Find first quote 472 | if (clockBegin == NULL) 473 | { 474 | free(command); 475 | free(response); 476 | return ""; 477 | } 478 | clockBegin += 1; // Increment pointer to begin at first number 479 | clockEnd = strchr(clockBegin, '\"'); // Find last quote 480 | if (clockEnd == NULL) 481 | { 482 | free(command); 483 | free(response); 484 | return ""; 485 | } 486 | *(clockEnd) = '\0'; // Set last quote to null char -- end string 487 | 488 | free(command); 489 | free(response); 490 | 491 | return String(clockBegin); 492 | } 493 | 494 | LTE_Shield_error_t LTE_Shield::clock(uint8_t *y, uint8_t *mo, uint8_t *d, 495 | uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz) 496 | { 497 | LTE_Shield_error_t err; 498 | char *command; 499 | char *response; 500 | char *clockBegin; 501 | char *clockEnd; 502 | 503 | int iy, imo, id, ih, imin, is, itz; 504 | 505 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_CLOCK) + 2); 506 | if (command == NULL) 507 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 508 | sprintf(command, "%s?", LTE_SHIELD_COMMAND_CLOCK); 509 | 510 | response = lte_calloc_char(48); 511 | if (response == NULL) 512 | { 513 | free(command); 514 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 515 | } 516 | 517 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 518 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 519 | 520 | // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n 521 | if (err == LTE_SHIELD_ERROR_SUCCESS) 522 | { 523 | if (sscanf(response, "\r\n+CCLK: \"%d/%d/%d,%d:%d:%d-%d\"\r\n", 524 | &iy, &imo, &id, &ih, &imin, &is, &itz) == 7) 525 | { 526 | *y = iy; 527 | *mo = imo; 528 | *d = id; 529 | *h = ih; 530 | *min = imin; 531 | *s = is; 532 | *tz = itz; 533 | } 534 | } 535 | 536 | free(command); 537 | free(response); 538 | return err; 539 | } 540 | 541 | LTE_Shield_error_t LTE_Shield::autoTimeZone(boolean enable) 542 | { 543 | LTE_Shield_error_t err; 544 | char *command; 545 | 546 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_AUTO_TZ) + 3); 547 | if (command == NULL) 548 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 549 | sprintf(command, "%s=%d", LTE_SHIELD_COMMAND_AUTO_TZ, enable ? 1 : 0); 550 | 551 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 552 | NULL, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 553 | free(command); 554 | return err; 555 | } 556 | 557 | int8_t LTE_Shield::rssi(void) 558 | { 559 | char *command; 560 | char *response; 561 | LTE_Shield_error_t err; 562 | int rssi; 563 | 564 | command = lte_calloc_char(strlen(LTE_SHIELD_SIGNAL_QUALITY) + 1); 565 | if (command == NULL) 566 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 567 | sprintf(command, "%s", LTE_SHIELD_SIGNAL_QUALITY); 568 | 569 | response = lte_calloc_char(48); 570 | if (response == NULL) 571 | { 572 | free(command); 573 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 574 | } 575 | 576 | err = sendCommandWithResponse(command, 577 | LTE_SHIELD_RESPONSE_OK, response, 10000, AT_COMMAND); 578 | if (err != LTE_SHIELD_ERROR_SUCCESS) 579 | { 580 | free(command); 581 | free(response); 582 | return -1; 583 | } 584 | 585 | if (sscanf(response, "\r\n+CSQ: %d,%*d", &rssi) != 1) 586 | { 587 | rssi = -1; 588 | } 589 | 590 | free(command); 591 | free(response); 592 | return rssi; 593 | } 594 | 595 | LTE_Shield_registration_status_t LTE_Shield::registration(void) 596 | { 597 | char *command; 598 | char *response; 599 | LTE_Shield_error_t err; 600 | int status; 601 | 602 | command = lte_calloc_char(strlen(LTE_SHIELD_REGISTRATION_STATUS) + 2); 603 | if (command == NULL) 604 | return LTE_SHIELD_REGISTRATION_INVALID; 605 | sprintf(command, "%s?", LTE_SHIELD_REGISTRATION_STATUS); 606 | 607 | response = lte_calloc_char(48); 608 | if (response == NULL) 609 | { 610 | free(command); 611 | return LTE_SHIELD_REGISTRATION_INVALID; 612 | } 613 | 614 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 615 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT, AT_COMMAND); 616 | if (err != LTE_SHIELD_ERROR_SUCCESS) 617 | { 618 | free(command); 619 | free(response); 620 | return LTE_SHIELD_REGISTRATION_INVALID; 621 | } 622 | 623 | if (sscanf(response, "\r\n+CREG: %*d,%d", &status) != 1) 624 | { 625 | status = LTE_SHIELD_REGISTRATION_INVALID; 626 | } 627 | free(command); 628 | free(response); 629 | return (LTE_Shield_registration_status_t)status; 630 | } 631 | 632 | boolean LTE_Shield::setNetwork(mobile_network_operator_t mno) 633 | { 634 | mobile_network_operator_t currentMno; 635 | 636 | // Check currently set MNO 637 | if (getMno(¤tMno) != LTE_SHIELD_ERROR_SUCCESS) 638 | { 639 | return false; 640 | } 641 | if (currentMno == mno) 642 | { 643 | return true; 644 | } 645 | 646 | if (functionality(MINIMUM_FUNCTIONALITY) != LTE_SHIELD_ERROR_SUCCESS) 647 | { 648 | return false; 649 | } 650 | 651 | if (setMno(mno) != LTE_SHIELD_ERROR_SUCCESS) 652 | { 653 | return false; 654 | } 655 | 656 | if (reset() != LTE_SHIELD_ERROR_SUCCESS) 657 | { 658 | return false; 659 | } 660 | 661 | return true; 662 | } 663 | 664 | mobile_network_operator_t LTE_Shield::getNetwork(void) 665 | { 666 | mobile_network_operator_t mno; 667 | LTE_Shield_error_t err; 668 | 669 | err = getMno(&mno); 670 | if (err != LTE_SHIELD_ERROR_SUCCESS) 671 | { 672 | return MNO_INVALID; 673 | } 674 | return mno; 675 | } 676 | 677 | LTE_Shield_error_t LTE_Shield::setAPN(String apn, uint8_t cid, LTE_Shield_pdp_type pdpType) 678 | { 679 | LTE_Shield_error_t err; 680 | char *command; 681 | char pdpStr[8]; 682 | 683 | memset(pdpStr, 0, 8); 684 | 685 | if (cid >= 8) 686 | return LTE_SHIELD_ERROR_UNEXPECTED_PARAM; 687 | 688 | command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_PDP_DEF) + strlen(apn.c_str()) + 16); 689 | if (command == NULL) 690 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 691 | switch (pdpType) 692 | { 693 | case PDP_TYPE_INVALID: 694 | free(command); 695 | return LTE_SHIELD_ERROR_UNEXPECTED_PARAM; 696 | break; 697 | case PDP_TYPE_IP: 698 | memcpy(pdpStr, "IP", 2); 699 | break; 700 | case PDP_TYPE_NONIP: 701 | memcpy(pdpStr, "NONIP", 2); 702 | break; 703 | case PDP_TYPE_IPV4V6: 704 | memcpy(pdpStr, "IPV4V6", 2); 705 | break; 706 | case PDP_TYPE_IPV6: 707 | memcpy(pdpStr, "IPV6", 2); 708 | break; 709 | } 710 | sprintf(command, "%s=%d,\"%s\",\"%s\"", LTE_SHIELD_MESSAGE_PDP_DEF, 711 | cid, pdpStr, apn.c_str()); 712 | 713 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 714 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 715 | 716 | free(command); 717 | 718 | return err; 719 | } 720 | 721 | LTE_Shield_error_t LTE_Shield::getAPN(String *apn, IPAddress *ip) 722 | { 723 | LTE_Shield_error_t err; 724 | char *command; 725 | char *response; 726 | char *searchPtr; 727 | int ipOctets[4]; 728 | 729 | command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_PDP_DEF) + 3); 730 | if (command == NULL) 731 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 732 | sprintf(command, "%s?", LTE_SHIELD_MESSAGE_PDP_DEF); 733 | 734 | response = lte_calloc_char(128); 735 | if (response == NULL) 736 | { 737 | free(command); 738 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 739 | } 740 | 741 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 742 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 743 | 744 | if (err == LTE_SHIELD_ERROR_SUCCESS) 745 | { 746 | // Example: +CGDCONT: 1,"IP","hologram","10.170.241.191",0,0,0,0 747 | searchPtr = strstr(response, "+CGDCONT: "); 748 | if (searchPtr != NULL) 749 | { 750 | searchPtr += strlen("+CGDCONT: "); 751 | // Search to the third double-quote 752 | for (int i = 0; i < 3; i++) 753 | { 754 | searchPtr = strchr(++searchPtr, '\"'); 755 | } 756 | if (searchPtr != NULL) 757 | { 758 | // Fill in the APN: 759 | searchPtr = strchr(searchPtr, '\"'); // Move to first quote 760 | while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) 761 | { 762 | apn->concat(*(searchPtr)); 763 | } 764 | // Now get the IP: 765 | if (searchPtr != NULL) 766 | { 767 | int scanned = sscanf(searchPtr, "\",\"%d.%d.%d.%d\"", 768 | &ipOctets[0], &ipOctets[1], &ipOctets[2], &ipOctets[3]); 769 | if (scanned == 4) 770 | { 771 | for (int octet = 0; octet < 4; octet++) 772 | { 773 | (*ip)[octet] = (uint8_t)ipOctets[octet]; 774 | } 775 | } 776 | } 777 | } 778 | } 779 | else 780 | { 781 | err = LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 782 | } 783 | } 784 | 785 | free(command); 786 | free(response); 787 | 788 | return err; 789 | } 790 | 791 | const char *PPP_L2P[5] = { 792 | "", 793 | "PPP", 794 | "M-HEX", 795 | "M-RAW_IP", 796 | "M-OPT-PPP", 797 | }; 798 | 799 | LTE_Shield_error_t LTE_Shield::enterPPP(uint8_t cid, char dialing_type_char, 800 | unsigned long dialNumber, LTE_Shield::LTE_Shield_l2p_t l2p) 801 | { 802 | LTE_Shield_error_t err; 803 | char *command; 804 | 805 | if ((dialing_type_char != 0) && (dialing_type_char != 'T') && 806 | (dialing_type_char != 'P')) 807 | { 808 | return LTE_SHIELD_ERROR_UNEXPECTED_PARAM; 809 | } 810 | 811 | command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_ENTER_PPP) + 32); 812 | if (command == NULL) 813 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 814 | if (dialing_type_char != 0) 815 | { 816 | sprintf(command, "%s%c*%lu**%s*%hhu#", LTE_SHIELD_MESSAGE_ENTER_PPP, dialing_type_char, 817 | dialNumber, PPP_L2P[l2p], cid); 818 | } 819 | else 820 | { 821 | sprintf(command, "%s*%lu**%s*%hhu#", LTE_SHIELD_MESSAGE_ENTER_PPP, 822 | dialNumber, PPP_L2P[l2p], cid); 823 | } 824 | 825 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 826 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 827 | 828 | free(command); 829 | return err; 830 | } 831 | 832 | uint8_t LTE_Shield::getOperators(struct operator_stats *opRet, int maxOps) 833 | { 834 | LTE_Shield_error_t err; 835 | char *command; 836 | char *response; 837 | uint8_t opsSeen = 0; 838 | 839 | command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 3); 840 | if (command == NULL) 841 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 842 | sprintf(command, "%s=?", LTE_SHIELD_OPERATOR_SELECTION); 843 | 844 | response = lte_calloc_char(maxOps * 48 + 16); 845 | if (response == NULL) 846 | { 847 | free(command); 848 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 849 | } 850 | 851 | // AT+COPS maximum response time is 3 minutes (180000 ms) 852 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 853 | 180000); 854 | 855 | // Sample responses: 856 | // +COPS: (3,"Verizon Wireless","VzW","311480",8),,(0,1,2,3,4),(0,1,2) 857 | // +COPS: (1,"313 100","313 100","313100",8),(2,"AT&T","AT&T","310410",8),(3,"311 480","311 480","311480",8),,(0,1,2,3,4),(0,1,2) 858 | 859 | if (err == LTE_SHIELD_ERROR_SUCCESS) 860 | { 861 | char *opBegin; 862 | char *opEnd; 863 | int op = 0; 864 | int sscanRead = 0; 865 | int stat; 866 | char longOp[26]; 867 | char shortOp[11]; 868 | int act; 869 | unsigned long numOp; 870 | 871 | opBegin = response; 872 | 873 | for (; op < maxOps; op++) 874 | { 875 | opBegin = strchr(opBegin, '('); 876 | if (opBegin == NULL) 877 | break; 878 | opEnd = strchr(opBegin, ')'); 879 | if (opEnd == NULL) 880 | break; 881 | 882 | int sscanRead = sscanf(opBegin, "(%d,\"%[^\"]\",\"%[^\"]\",\"%lu\",%d)%*s", 883 | &stat, longOp, shortOp, &numOp, &act); 884 | if (sscanRead == 5) 885 | { 886 | opRet[op].stat = stat; 887 | opRet[op].longOp = (String)(longOp); 888 | opRet[op].shortOp = (String)(shortOp); 889 | opRet[op].numOp = numOp; 890 | opRet[op].act = act; 891 | opsSeen += 1; 892 | } 893 | // TODO: Search for other possible patterns here 894 | else 895 | { 896 | break; // Break out if pattern doesn't match. 897 | } 898 | opBegin = opEnd + 1; // Move opBegin to beginning of next value 899 | } 900 | } 901 | 902 | free(command); 903 | free(response); 904 | 905 | return opsSeen; 906 | } 907 | 908 | LTE_Shield_error_t LTE_Shield::registerOperator(struct operator_stats oper) 909 | { 910 | LTE_Shield_error_t err; 911 | char *command; 912 | 913 | command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 24); 914 | if (command == NULL) 915 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 916 | sprintf(command, "%s=1,2,\"%lu\"", LTE_SHIELD_OPERATOR_SELECTION, oper.numOp); 917 | 918 | // AT+COPS maximum response time is 3 minutes (180000 ms) 919 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 920 | 180000); 921 | 922 | free(command); 923 | return err; 924 | } 925 | 926 | LTE_Shield_error_t LTE_Shield::getOperator(String *oper) 927 | { 928 | LTE_Shield_error_t err; 929 | char *command; 930 | char *response; 931 | char *searchPtr; 932 | char mode; 933 | 934 | command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 3); 935 | if (command == NULL) 936 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 937 | sprintf(command, "%s?", LTE_SHIELD_OPERATOR_SELECTION); 938 | 939 | response = lte_calloc_char(64); 940 | if (response == NULL) 941 | { 942 | free(command); 943 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 944 | } 945 | 946 | // AT+COPS maximum response time is 3 minutes (180000 ms) 947 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 948 | 180000); 949 | 950 | if (err == LTE_SHIELD_ERROR_SUCCESS) 951 | { 952 | searchPtr = strstr(response, "+COPS: "); 953 | if (searchPtr != NULL) 954 | { 955 | searchPtr += strlen("+COPS: "); // Move searchPtr to first char 956 | mode = *searchPtr; // Read first char -- should be mode 957 | if (mode == '2') // Check for de-register 958 | { 959 | err = LTE_SHIELD_ERROR_DEREGISTERED; 960 | } 961 | // Otherwise if it's default, manual, set-only, or automatic 962 | else if ((mode == '0') || (mode == '1') || (mode == '3') || (mode == '4')) 963 | { 964 | *oper = ""; 965 | searchPtr = strchr(searchPtr, '\"'); // Move to first quote 966 | if (searchPtr == NULL) 967 | { 968 | err = LTE_SHIELD_ERROR_DEREGISTERED; 969 | } 970 | else 971 | { 972 | while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) 973 | { 974 | oper->concat(*(searchPtr)); 975 | } 976 | } 977 | //Serial.println("Operator: " + *oper); 978 | //oper->concat('\0'); 979 | } 980 | } 981 | } 982 | 983 | free(response); 984 | free(command); 985 | return err; 986 | } 987 | 988 | LTE_Shield_error_t LTE_Shield::deregisterOperator(void) 989 | { 990 | LTE_Shield_error_t err; 991 | char *command; 992 | 993 | command = lte_calloc_char(strlen(LTE_SHIELD_OPERATOR_SELECTION) + 4); 994 | if (command == NULL) 995 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 996 | sprintf(command, "%s=2", LTE_SHIELD_OPERATOR_SELECTION); 997 | 998 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 999 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1000 | 1001 | free(command); 1002 | return err; 1003 | } 1004 | 1005 | LTE_Shield_error_t LTE_Shield::setSMSMessageFormat(lte_shield_message_format_t textMode) 1006 | { 1007 | char *command; 1008 | LTE_Shield_error_t err; 1009 | 1010 | command = lte_calloc_char(strlen(LTE_SHIELD_MESSAGE_FORMAT) + 4); 1011 | if (command == NULL) 1012 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1013 | sprintf(command, "%s=%d", LTE_SHIELD_MESSAGE_FORMAT, 1014 | (textMode == LTE_SHIELD_MESSAGE_FORMAT_TEXT) ? 1 : 0); 1015 | 1016 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 1017 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1018 | 1019 | free(command); 1020 | return err; 1021 | } 1022 | 1023 | LTE_Shield_error_t LTE_Shield::sendSMS(String number, String message) 1024 | { 1025 | char *command; 1026 | char *messageCStr; 1027 | char *numberCStr; 1028 | int messageIndex; 1029 | LTE_Shield_error_t err; 1030 | 1031 | numberCStr = lte_calloc_char(number.length() + 2); 1032 | if (numberCStr == NULL) 1033 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1034 | number.toCharArray(numberCStr, number.length() + 1); 1035 | 1036 | command = lte_calloc_char(strlen(LTE_SHIELD_SEND_TEXT) + strlen(numberCStr) + 8); 1037 | if (command != NULL) 1038 | { 1039 | sprintf(command, "%s=\"%s\"", LTE_SHIELD_SEND_TEXT, numberCStr); 1040 | 1041 | err = sendCommandWithResponse(command, ">", NULL, 1042 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1043 | free(command); 1044 | free(numberCStr); 1045 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1046 | return err; 1047 | 1048 | messageCStr = lte_calloc_char(message.length() + 1); 1049 | if (messageCStr == NULL) 1050 | { 1051 | hwWrite(ASCII_CTRL_Z); 1052 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1053 | } 1054 | message.toCharArray(messageCStr, message.length() + 1); 1055 | messageCStr[message.length()] = ASCII_CTRL_Z; 1056 | 1057 | err = sendCommandWithResponse(messageCStr, LTE_SHIELD_RESPONSE_OK, 1058 | NULL, 180000, NOT_AT_COMMAND); 1059 | 1060 | free(messageCStr); 1061 | } 1062 | else 1063 | { 1064 | free(numberCStr); 1065 | err = LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1066 | } 1067 | 1068 | return err; 1069 | } 1070 | 1071 | LTE_Shield_error_t LTE_Shield::setBaud(unsigned long baud) 1072 | { 1073 | LTE_Shield_error_t err; 1074 | char *command; 1075 | int b = 0; 1076 | 1077 | // Error check -- ensure supported baud 1078 | for (; b < NUM_SUPPORTED_BAUD; b++) 1079 | { 1080 | if (LTE_SHIELD_SUPPORTED_BAUD[b] == baud) 1081 | { 1082 | break; 1083 | } 1084 | } 1085 | if (b >= NUM_SUPPORTED_BAUD) 1086 | { 1087 | return LTE_SHIELD_ERROR_UNEXPECTED_PARAM; 1088 | } 1089 | 1090 | // Construct command 1091 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_BAUD) + 7 + 12); 1092 | if (command == NULL) 1093 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1094 | sprintf(command, "%s=%lu", LTE_SHIELD_COMMAND_BAUD, baud); 1095 | 1096 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1097 | NULL, LTE_SHIELD_SET_BAUD_TIMEOUT); 1098 | 1099 | free(command); 1100 | 1101 | return err; 1102 | } 1103 | 1104 | LTE_Shield_error_t LTE_Shield::setGpioMode(LTE_Shield_gpio_t gpio, 1105 | LTE_Shield_gpio_mode_t mode) 1106 | { 1107 | LTE_Shield_error_t err; 1108 | char *command; 1109 | 1110 | // Example command: AT+UGPIOC=16,2 1111 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_GPIO) + 7); 1112 | if (command == NULL) 1113 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1114 | sprintf(command, "%s=%d,%d", LTE_SHIELD_COMMAND_GPIO, gpio, mode); 1115 | 1116 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1117 | NULL, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1118 | 1119 | free(command); 1120 | 1121 | return err; 1122 | } 1123 | 1124 | LTE_Shield::LTE_Shield_gpio_mode_t LTE_Shield::getGpioMode(LTE_Shield_gpio_t gpio) 1125 | { 1126 | LTE_Shield_error_t err; 1127 | char *command; 1128 | char *response; 1129 | char gpioChar[4]; 1130 | char *gpioStart; 1131 | int gpioMode; 1132 | 1133 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_GPIO) + 2); 1134 | if (command == NULL) 1135 | return GPIO_MODE_INVALID; 1136 | sprintf(command, "%s?", LTE_SHIELD_COMMAND_GPIO); 1137 | 1138 | response = lte_calloc_char(96); 1139 | if (response == NULL) 1140 | { 1141 | free(command); 1142 | return GPIO_MODE_INVALID; 1143 | } 1144 | 1145 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1146 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1147 | 1148 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1149 | { 1150 | free(command); 1151 | free(response); 1152 | return GPIO_MODE_INVALID; 1153 | } 1154 | 1155 | sprintf(gpioChar, "%d", gpio); // Convert GPIO to char array 1156 | gpioStart = strstr(response, gpioChar); // Find first occurence of GPIO in response 1157 | 1158 | free(command); 1159 | free(response); 1160 | 1161 | if (gpioStart == NULL) 1162 | return GPIO_MODE_INVALID; // If not found return invalid 1163 | sscanf(gpioStart, "%*d,%d\r\n", &gpioMode); 1164 | 1165 | return (LTE_Shield_gpio_mode_t)gpioMode; 1166 | } 1167 | 1168 | int LTE_Shield::socketOpen(lte_shield_socket_protocol_t protocol, unsigned int localPort) 1169 | { 1170 | LTE_Shield_error_t err; 1171 | char *command; 1172 | char *response; 1173 | int sockId = -1; 1174 | char *responseStart; 1175 | 1176 | command = lte_calloc_char(strlen(LTE_SHIELD_CREATE_SOCKET) + 10); 1177 | if (command == NULL) 1178 | return -1; 1179 | sprintf(command, "%s=%d,%d", LTE_SHIELD_CREATE_SOCKET, protocol, localPort); 1180 | 1181 | response = lte_calloc_char(24); 1182 | if (response == NULL) 1183 | { 1184 | free(command); 1185 | return -1; 1186 | } 1187 | 1188 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1189 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1190 | 1191 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1192 | { 1193 | free(command); 1194 | free(response); 1195 | return -1; 1196 | } 1197 | 1198 | responseStart = strstr(response, "+USOCR"); 1199 | if (responseStart == NULL) 1200 | { 1201 | free(command); 1202 | free(response); 1203 | return -1; 1204 | } 1205 | 1206 | sscanf(responseStart, "+USOCR: %d", &sockId); 1207 | 1208 | free(command); 1209 | free(response); 1210 | 1211 | return sockId; 1212 | } 1213 | 1214 | LTE_Shield_error_t LTE_Shield::socketClose(int socket, int timeout) 1215 | { 1216 | LTE_Shield_error_t err; 1217 | char *command; 1218 | 1219 | command = lte_calloc_char(strlen(LTE_SHIELD_CLOSE_SOCKET) + 10); 1220 | if (command == NULL) 1221 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1222 | sprintf(command, "%s=%d", LTE_SHIELD_CLOSE_SOCKET, socket); 1223 | 1224 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, timeout); 1225 | 1226 | free(command); 1227 | 1228 | return err; 1229 | } 1230 | 1231 | LTE_Shield_error_t LTE_Shield::socketConnect(int socket, const char *address, 1232 | unsigned int port) 1233 | { 1234 | LTE_Shield_error_t err; 1235 | char *command; 1236 | 1237 | command = lte_calloc_char(strlen(LTE_SHIELD_CONNECT_SOCKET) + strlen(address) + 11); 1238 | if (command == NULL) 1239 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1240 | sprintf(command, "%s=%d,\"%s\",%d", LTE_SHIELD_CONNECT_SOCKET, socket, address, port); 1241 | 1242 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, LTE_SHIELD_IP_CONNECT_TIMEOUT); 1243 | 1244 | free(command); 1245 | 1246 | return err; 1247 | } 1248 | 1249 | LTE_Shield_error_t LTE_Shield::socketWrite(int socket, const char *str) 1250 | { 1251 | char *command; 1252 | LTE_Shield_error_t err; 1253 | 1254 | command = lte_calloc_char(strlen(LTE_SHIELD_WRITE_SOCKET) + 8); 1255 | if (command == NULL) 1256 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1257 | sprintf(command, "%s=%d,%d", LTE_SHIELD_WRITE_SOCKET, socket, strlen(str)); 1258 | 1259 | err = sendCommandWithResponse(command, "@", NULL, 1260 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1261 | 1262 | hwPrint(str); 1263 | 1264 | err = waitForResponse(LTE_SHIELD_RESPONSE_OK, LTE_SHIELD_SOCKET_WRITE_TIMEOUT); 1265 | 1266 | free(command); 1267 | return err; 1268 | } 1269 | 1270 | LTE_Shield_error_t LTE_Shield::socketWrite(int socket, String str) 1271 | { 1272 | return socketWrite(socket, str.c_str()); 1273 | } 1274 | 1275 | LTE_Shield_error_t LTE_Shield::socketRead(int socket, int length, char *readDest) 1276 | { 1277 | char *command; 1278 | char *response; 1279 | char *strBegin; 1280 | int readIndex = 0; 1281 | LTE_Shield_error_t err; 1282 | 1283 | command = lte_calloc_char(strlen(LTE_SHIELD_READ_SOCKET) + 8); 1284 | if (command == NULL) 1285 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1286 | sprintf(command, "%s=%d,%d", LTE_SHIELD_READ_SOCKET, socket, length); 1287 | 1288 | response = lte_calloc_char(length + strlen(LTE_SHIELD_READ_SOCKET) + 24); 1289 | if (response == NULL) 1290 | { 1291 | free(command); 1292 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1293 | } 1294 | 1295 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 1296 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1297 | 1298 | if (err == LTE_SHIELD_ERROR_SUCCESS) 1299 | { 1300 | // Find the first double-quote: 1301 | strBegin = strchr(response, '\"'); 1302 | 1303 | if (strBegin == NULL) 1304 | { 1305 | free(command); 1306 | free(response); 1307 | return LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1308 | } 1309 | 1310 | while ((readIndex < length) && (readIndex < strlen(strBegin))) 1311 | { 1312 | readDest[readIndex] = strBegin[1 + readIndex]; 1313 | readIndex += 1; 1314 | } 1315 | } 1316 | 1317 | free(command); 1318 | free(response); 1319 | 1320 | return err; 1321 | } 1322 | 1323 | LTE_Shield_error_t LTE_Shield::socketListen(int socket, unsigned int port) 1324 | { 1325 | LTE_Shield_error_t err; 1326 | char *command; 1327 | 1328 | command = lte_calloc_char(strlen(LTE_SHIELD_LISTEN_SOCKET) + 9); 1329 | if (command == NULL) 1330 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1331 | sprintf(command, "%s=%d,%d", LTE_SHIELD_LISTEN_SOCKET, socket, port); 1332 | 1333 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 1334 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1335 | 1336 | free(command); 1337 | return err; 1338 | } 1339 | 1340 | IPAddress LTE_Shield::lastRemoteIP(void) 1341 | { 1342 | return _lastRemoteIP; 1343 | } 1344 | 1345 | boolean LTE_Shield::gpsOn(void) 1346 | { 1347 | LTE_Shield_error_t err; 1348 | char *command; 1349 | char *response; 1350 | boolean on = false; 1351 | 1352 | command = lte_calloc_char(strlen(LTE_SHIELD_GPS_POWER) + 2); 1353 | if (command == NULL) 1354 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1355 | sprintf(command, "%s?", LTE_SHIELD_GPS_POWER); 1356 | 1357 | response = lte_calloc_char(24); 1358 | if (response == NULL) 1359 | { 1360 | free(command); 1361 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1362 | } 1363 | 1364 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 1365 | LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1366 | 1367 | if (err == LTE_SHIELD_ERROR_SUCCESS) 1368 | { 1369 | // Example response: "+UGPS: 0" for off "+UGPS: 1,0,1" for on 1370 | // May be too lazy/simple, but just search for a '1' 1371 | if (strchr(response, '1') != NULL) 1372 | on = true; 1373 | } 1374 | 1375 | free(command); 1376 | free(response); 1377 | 1378 | return on; 1379 | } 1380 | 1381 | LTE_Shield_error_t LTE_Shield::gpsPower(boolean enable, gnss_system_t gnss_sys) 1382 | { 1383 | LTE_Shield_error_t err; 1384 | char *command; 1385 | boolean gpsState; 1386 | 1387 | // Don't turn GPS on/off if it's already on/off 1388 | gpsState = gpsOn(); 1389 | if ((enable && gpsState) || (!enable && !gpsState)) 1390 | { 1391 | return LTE_SHIELD_ERROR_SUCCESS; 1392 | } 1393 | 1394 | command = lte_calloc_char(strlen(LTE_SHIELD_GPS_POWER) + 8); 1395 | if (command == NULL) 1396 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1397 | if (enable) 1398 | { 1399 | sprintf(command, "%s=1,0,%d", LTE_SHIELD_GPS_POWER, gnss_sys); 1400 | } 1401 | else 1402 | { 1403 | sprintf(command, "%s=0", LTE_SHIELD_GPS_POWER); 1404 | } 1405 | 1406 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 10000); 1407 | 1408 | free(command); 1409 | return err; 1410 | } 1411 | 1412 | LTE_Shield_error_t LTE_Shield::gpsEnableClock(boolean enable) 1413 | { 1414 | // AT+UGZDA=<0,1> 1415 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1416 | return err; 1417 | } 1418 | 1419 | LTE_Shield_error_t LTE_Shield::gpsGetClock(struct ClockData *clock) 1420 | { 1421 | // AT+UGZDA? 1422 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1423 | return err; 1424 | } 1425 | 1426 | LTE_Shield_error_t LTE_Shield::gpsEnableFix(boolean enable) 1427 | { 1428 | // AT+UGGGA=<0,1> 1429 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1430 | return err; 1431 | } 1432 | 1433 | LTE_Shield_error_t LTE_Shield::gpsGetFix(struct PositionData *pos) 1434 | { 1435 | // AT+UGGGA? 1436 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1437 | return err; 1438 | } 1439 | 1440 | LTE_Shield_error_t LTE_Shield::gpsEnablePos(boolean enable) 1441 | { 1442 | // AT+UGGLL=<0,1> 1443 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1444 | return err; 1445 | } 1446 | 1447 | LTE_Shield_error_t LTE_Shield::gpsGetPos(struct PositionData *pos) 1448 | { 1449 | // AT+UGGLL? 1450 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1451 | return err; 1452 | } 1453 | 1454 | LTE_Shield_error_t LTE_Shield::gpsEnableSat(boolean enable) 1455 | { 1456 | // AT+UGGSV=<0,1> 1457 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1458 | return err; 1459 | } 1460 | 1461 | LTE_Shield_error_t LTE_Shield::gpsGetSat(uint8_t *sats) 1462 | { 1463 | // AT+UGGSV? 1464 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1465 | return err; 1466 | } 1467 | 1468 | LTE_Shield_error_t LTE_Shield::gpsEnableRmc(boolean enable) 1469 | { 1470 | // AT+UGRMC=<0,1> 1471 | LTE_Shield_error_t err; 1472 | char *command; 1473 | 1474 | if (!gpsOn()) 1475 | { 1476 | err = gpsPower(true); 1477 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1478 | { 1479 | return err; 1480 | } 1481 | } 1482 | 1483 | command = lte_calloc_char(strlen(LTE_SHIELD_GPS_GPRMC) + 3); 1484 | if (command == NULL) 1485 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1486 | sprintf(command, "%s=%d", LTE_SHIELD_GPS_GPRMC, enable ? 1 : 0); 1487 | 1488 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 10000); 1489 | 1490 | free(command); 1491 | return err; 1492 | } 1493 | 1494 | LTE_Shield_error_t LTE_Shield::gpsGetRmc(struct PositionData *pos, struct SpeedData *spd, 1495 | struct ClockData *clk, boolean *valid) 1496 | { 1497 | LTE_Shield_error_t err; 1498 | char *command; 1499 | char *response; 1500 | char *rmcBegin; 1501 | 1502 | command = lte_calloc_char(strlen(LTE_SHIELD_GPS_GPRMC) + 2); 1503 | if (command == NULL) 1504 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1505 | sprintf(command, "%s?", LTE_SHIELD_GPS_GPRMC); 1506 | 1507 | response = lte_calloc_char(96); 1508 | if (response == NULL) 1509 | { 1510 | free(command); 1511 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1512 | } 1513 | 1514 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, response, 10000); 1515 | if (err == LTE_SHIELD_ERROR_SUCCESS) 1516 | { 1517 | // Fast-forward response string to $GPRMC starter 1518 | rmcBegin = strstr(response, "$GPRMC"); 1519 | if (rmcBegin == NULL) 1520 | { 1521 | err = LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1522 | } 1523 | else 1524 | { 1525 | *valid = parseGPRMCString(rmcBegin, pos, clk, spd); 1526 | } 1527 | } 1528 | 1529 | free(command); 1530 | free(response); 1531 | return err; 1532 | } 1533 | 1534 | LTE_Shield_error_t LTE_Shield::gpsEnableSpeed(boolean enable) 1535 | { 1536 | // AT+UGVTG=<0,1> 1537 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1538 | return err; 1539 | } 1540 | 1541 | LTE_Shield_error_t LTE_Shield::gpsGetSpeed(struct SpeedData *speed) 1542 | { 1543 | // AT+UGVTG? 1544 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_SUCCESS; 1545 | return err; 1546 | } 1547 | 1548 | LTE_Shield_error_t LTE_Shield::gpsRequest(unsigned int timeout, uint32_t accuracy, 1549 | boolean detailed) 1550 | { 1551 | // AT+ULOC=2,,,, 1552 | LTE_Shield_error_t err; 1553 | char *command; 1554 | 1555 | // This function will only work if the GPS module is initially turned off. 1556 | if (gpsOn()) 1557 | { 1558 | gpsPower(false); 1559 | } 1560 | 1561 | if (timeout > 999) 1562 | timeout = 999; 1563 | if (accuracy > 999999) 1564 | accuracy = 999999; 1565 | 1566 | command = lte_calloc_char(strlen(LTE_SHIELD_GPS_REQUEST_LOCATION) + 24); 1567 | if (command == NULL) 1568 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1569 | sprintf(command, "%s=2,3,%d,%d,%d", LTE_SHIELD_GPS_REQUEST_LOCATION, 1570 | detailed ? 1 : 0, timeout, accuracy); 1571 | 1572 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, NULL, 10000); 1573 | 1574 | free(command); 1575 | return err; 1576 | } 1577 | 1578 | ///////////// 1579 | // Private // 1580 | ///////////// 1581 | 1582 | LTE_Shield_error_t LTE_Shield::init(unsigned long baud, 1583 | LTE_Shield::LTE_Shield_init_type_t initType) 1584 | { 1585 | LTE_Shield_error_t err; 1586 | 1587 | beginSerial(baud); // Begin serial 1588 | 1589 | if (initType == LTE_SHIELD_INIT_AUTOBAUD) 1590 | { 1591 | if (autobaud(baud) != LTE_SHIELD_ERROR_SUCCESS) 1592 | { 1593 | return init(baud, LTE_SHIELD_INIT_RESET); 1594 | } 1595 | } 1596 | else if (initType == LTE_SHIELD_INIT_RESET) 1597 | { 1598 | powerOn(); 1599 | if (at() != LTE_SHIELD_ERROR_SUCCESS) 1600 | { 1601 | return init(baud, LTE_SHIELD_INIT_AUTOBAUD); 1602 | } 1603 | } 1604 | 1605 | // Use disable echo to test response 1606 | err = enableEcho(false); 1607 | 1608 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1609 | return init(baud, LTE_SHIELD_INIT_AUTOBAUD); 1610 | 1611 | _baud = baud; 1612 | setGpioMode(GPIO1, NETWORK_STATUS); 1613 | setGpioMode(GPIO2, GNSS_SUPPLY_ENABLE); 1614 | setSMSMessageFormat(LTE_SHIELD_MESSAGE_FORMAT_TEXT); 1615 | autoTimeZone(true); 1616 | for (int i = 0; i < LTE_SHIELD_NUM_SOCKETS; i++) 1617 | { 1618 | socketClose(i, 100); 1619 | } 1620 | 1621 | return LTE_SHIELD_ERROR_SUCCESS; 1622 | } 1623 | 1624 | void LTE_Shield::powerOn(void) 1625 | { 1626 | pinMode(_powerPin, OUTPUT); 1627 | digitalWrite(_powerPin, LOW); 1628 | delay(LTE_SHIELD_POWER_PULSE_PERIOD); 1629 | pinMode(_powerPin, INPUT); // Return to high-impedance, rely on SARA module internal pull-up 1630 | } 1631 | 1632 | void LTE_Shield::hwReset(void) 1633 | { 1634 | pinMode(_resetPin, OUTPUT); 1635 | digitalWrite(_resetPin, LOW); 1636 | delay(LTE_RESET_PULSE_PERIOD); 1637 | pinMode(_resetPin, INPUT); // Return to high-impedance, rely on SARA module internal pull-up 1638 | } 1639 | 1640 | LTE_Shield_error_t LTE_Shield::functionality(LTE_Shield_functionality_t function) 1641 | { 1642 | LTE_Shield_error_t err; 1643 | char *command; 1644 | 1645 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_FUNC) + 4); 1646 | if (command == NULL) 1647 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1648 | sprintf(command, "%s=%d", LTE_SHIELD_COMMAND_FUNC, function); 1649 | 1650 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1651 | NULL, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1652 | 1653 | free(command); 1654 | 1655 | return err; 1656 | } 1657 | 1658 | LTE_Shield_error_t LTE_Shield::setMno(mobile_network_operator_t mno) 1659 | { 1660 | LTE_Shield_error_t err; 1661 | char *command; 1662 | 1663 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_MNO) + 3); 1664 | if (command == NULL) 1665 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1666 | sprintf(command, "%s=%d", LTE_SHIELD_COMMAND_MNO, (uint8_t)mno); 1667 | 1668 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1669 | NULL, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1670 | 1671 | free(command); 1672 | 1673 | return err; 1674 | } 1675 | 1676 | LTE_Shield_error_t LTE_Shield::getMno(mobile_network_operator_t *mno) 1677 | { 1678 | LTE_Shield_error_t err; 1679 | char *command; 1680 | char *response; 1681 | const char *mno_keys = "0123456"; // Valid MNO responses 1682 | int i; 1683 | 1684 | command = lte_calloc_char(strlen(LTE_SHIELD_COMMAND_MNO) + 2); 1685 | if (command == NULL) 1686 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1687 | sprintf(command, "%s?", LTE_SHIELD_COMMAND_MNO); 1688 | 1689 | response = lte_calloc_char(24); 1690 | if (response == NULL) 1691 | { 1692 | free(command); 1693 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1694 | } 1695 | 1696 | err = sendCommandWithResponse(command, LTE_SHIELD_RESPONSE_OK, 1697 | response, LTE_SHIELD_STANDARD_RESPONSE_TIMEOUT); 1698 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1699 | { 1700 | free(command); 1701 | free(response); 1702 | return err; 1703 | } 1704 | 1705 | i = strcspn(response, mno_keys); // Find first occurence of MNO key 1706 | if (i == strlen(response)) 1707 | { 1708 | *mno = MNO_INVALID; 1709 | free(command); 1710 | free(response); 1711 | return LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1712 | } 1713 | *mno = (mobile_network_operator_t)(response[i] - 0x30); // Convert to integer 1714 | 1715 | free(command); 1716 | free(response); 1717 | 1718 | return err; 1719 | } 1720 | 1721 | /*LTE_Shield_error_t LTE_Shield::sendCommandWithResponseAndTimeout(const char * command, 1722 | char * expectedResponse, uint16_t commandTimeout, boolean at) 1723 | { 1724 | unsigned long timeIn = millis(); 1725 | char * response; 1726 | 1727 | sendCommand(command, at); 1728 | 1729 | // Wait until we've receved the requested number of characters 1730 | while (hwAvailable() < strlen(expectedResponse)) 1731 | { 1732 | if (millis() > timeIn + commandTimeout) 1733 | { 1734 | return LTE_SHIELD_ERROR_TIMEOUT; 1735 | } 1736 | } 1737 | response = lte_calloc_char(hwAvailable() + 1); 1738 | if (response == NULL) 1739 | { 1740 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1741 | } 1742 | readAvailable(response); 1743 | 1744 | // Check for expected response 1745 | if (strcmp(response, expectedResponse) == 0) 1746 | { 1747 | return LTE_SHIELD_ERROR_SUCCESS; 1748 | } 1749 | return LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1750 | }*/ 1751 | 1752 | LTE_Shield_error_t LTE_Shield::waitForResponse(const char *expectedResponse, uint16_t timeout) 1753 | { 1754 | unsigned long timeIn; 1755 | boolean found = false; 1756 | int index = 0; 1757 | 1758 | timeIn = millis(); 1759 | 1760 | while ((!found) && (timeIn + timeout > millis())) 1761 | { 1762 | if (hwAvailable()) 1763 | { 1764 | char c = readChar(); 1765 | if (c == expectedResponse[index]) 1766 | { 1767 | if (++index == strlen(expectedResponse)) 1768 | { 1769 | found = true; 1770 | } 1771 | } 1772 | else 1773 | { 1774 | index = 0; 1775 | } 1776 | } 1777 | } 1778 | return found ? LTE_SHIELD_ERROR_SUCCESS : LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1779 | } 1780 | 1781 | LTE_Shield_error_t LTE_Shield::sendCommandWithResponse( 1782 | const char *command, const char *expectedResponse, char *responseDest, 1783 | unsigned long commandTimeout, boolean at) 1784 | { 1785 | unsigned long timeIn; 1786 | boolean found = false; 1787 | int index = 0; 1788 | int destIndex = 0; 1789 | unsigned int charsRead = 0; 1790 | 1791 | //Serial.print("Command: "); 1792 | //Serial.println(String(command)); 1793 | sendCommand(command, at); 1794 | //Serial.print("Response: "); 1795 | timeIn = millis(); 1796 | while ((!found) && (timeIn + commandTimeout > millis())) 1797 | { 1798 | if (hwAvailable()) 1799 | { 1800 | char c = readChar(); 1801 | //Serial.write(c); 1802 | if (responseDest != NULL) 1803 | { 1804 | responseDest[destIndex++] = c; 1805 | } 1806 | charsRead++; 1807 | if (c == expectedResponse[index]) 1808 | { 1809 | if (++index == strlen(expectedResponse)) 1810 | { 1811 | found = true; 1812 | } 1813 | } 1814 | else 1815 | { 1816 | index = 0; 1817 | } 1818 | } 1819 | } 1820 | //Serial.println(); 1821 | 1822 | if (found) 1823 | { 1824 | return LTE_SHIELD_ERROR_SUCCESS; 1825 | } 1826 | else if (charsRead == 0) 1827 | { 1828 | return LTE_SHIELD_ERROR_NO_RESPONSE; 1829 | } 1830 | else 1831 | { 1832 | return LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1833 | } 1834 | } 1835 | 1836 | boolean LTE_Shield::sendCommand(const char *command, boolean at) 1837 | { 1838 | readAvailable(NULL); // Clear out receive buffer before sending a new command 1839 | 1840 | if (at) 1841 | { 1842 | hwPrint(LTE_SHIELD_COMMAND_AT); 1843 | hwPrint(command); 1844 | hwPrint("\r"); 1845 | } 1846 | else 1847 | { 1848 | hwPrint(command); 1849 | } 1850 | 1851 | return true; 1852 | } 1853 | 1854 | LTE_Shield_error_t LTE_Shield::parseSocketReadIndication(int socket, int length) 1855 | { 1856 | LTE_Shield_error_t err; 1857 | char *readDest; 1858 | 1859 | if ((socket < 0) || (length < 0)) 1860 | { 1861 | return LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE; 1862 | } 1863 | 1864 | readDest = lte_calloc_char(length + 1); 1865 | if (readDest == NULL) 1866 | return LTE_SHIELD_ERROR_OUT_OF_MEMORY; 1867 | 1868 | err = socketRead(socket, length, readDest); 1869 | if (err != LTE_SHIELD_ERROR_SUCCESS) 1870 | { 1871 | free(readDest); 1872 | return err; 1873 | } 1874 | 1875 | if (_socketReadCallback != NULL) 1876 | { 1877 | _socketReadCallback(socket, String(readDest)); 1878 | } 1879 | 1880 | free(readDest); 1881 | return LTE_SHIELD_ERROR_SUCCESS; 1882 | } 1883 | 1884 | LTE_Shield_error_t LTE_Shield::parseSocketListenIndication(IPAddress localIP, IPAddress remoteIP) 1885 | { 1886 | _lastLocalIP = localIP; 1887 | _lastRemoteIP = remoteIP; 1888 | return LTE_SHIELD_ERROR_SUCCESS; 1889 | } 1890 | 1891 | LTE_Shield_error_t LTE_Shield::parseSocketCloseIndication(String *closeIndication) 1892 | { 1893 | LTE_Shield_error_t err; 1894 | int search; 1895 | int socket; 1896 | 1897 | search = closeIndication->indexOf("UUSOCL: ") + strlen("UUSOCL: "); 1898 | 1899 | // Socket will be first integer, should be single-digit number between 0-6: 1900 | socket = closeIndication->substring(search, search + 1).toInt(); 1901 | 1902 | if (_socketCloseCallback != NULL) 1903 | { 1904 | _socketCloseCallback(socket); 1905 | } 1906 | 1907 | return LTE_SHIELD_ERROR_SUCCESS; 1908 | } 1909 | 1910 | size_t LTE_Shield::hwPrint(const char *s) 1911 | { 1912 | if (_hardSerial != NULL) 1913 | { 1914 | return _hardSerial->print(s); 1915 | } 1916 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 1917 | else if (_softSerial != NULL) 1918 | { 1919 | return _softSerial->print(s); 1920 | } 1921 | #endif 1922 | 1923 | return (size_t)0; 1924 | } 1925 | 1926 | size_t LTE_Shield::hwWrite(const char c) 1927 | { 1928 | if (_hardSerial != NULL) 1929 | { 1930 | return _hardSerial->write(c); 1931 | } 1932 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 1933 | else if (_softSerial != NULL) 1934 | { 1935 | return _softSerial->write(c); 1936 | } 1937 | #endif 1938 | 1939 | return (size_t)0; 1940 | } 1941 | 1942 | int LTE_Shield::readAvailable(char *inString) 1943 | { 1944 | int len = 0; 1945 | 1946 | if (_hardSerial != NULL) 1947 | { 1948 | while (_hardSerial->available()) 1949 | { 1950 | char c = (char)_hardSerial->read(); 1951 | if (inString != NULL) 1952 | { 1953 | inString[len++] = c; 1954 | } 1955 | } 1956 | if (inString != NULL) 1957 | { 1958 | inString[len] = 0; 1959 | } 1960 | } 1961 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 1962 | if (_softSerial != NULL) 1963 | { 1964 | while (_softSerial->available()) 1965 | { 1966 | char c = (char)_softSerial->read(); 1967 | if (inString != NULL) 1968 | { 1969 | inString[len++] = c; 1970 | } 1971 | } 1972 | if (inString != NULL) 1973 | { 1974 | inString[len] = 0; 1975 | } 1976 | } 1977 | #endif 1978 | 1979 | return len; 1980 | } 1981 | 1982 | char LTE_Shield::readChar(void) 1983 | { 1984 | char ret; 1985 | 1986 | if (_hardSerial != NULL) 1987 | { 1988 | ret = (char)_hardSerial->read(); 1989 | } 1990 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 1991 | else if (_softSerial != NULL) 1992 | { 1993 | ret = (char)_softSerial->read(); 1994 | } 1995 | #endif 1996 | 1997 | return ret; 1998 | } 1999 | 2000 | int LTE_Shield::hwAvailable(void) 2001 | { 2002 | if (_hardSerial != NULL) 2003 | { 2004 | return _hardSerial->available(); 2005 | } 2006 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 2007 | else if (_softSerial != NULL) 2008 | { 2009 | return _softSerial->available(); 2010 | } 2011 | #endif 2012 | 2013 | return -1; 2014 | } 2015 | 2016 | void LTE_Shield::beginSerial(unsigned long baud) 2017 | { 2018 | if (_hardSerial != NULL) 2019 | { 2020 | _hardSerial->begin(baud); 2021 | } 2022 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 2023 | else if (_softSerial != NULL) 2024 | { 2025 | _softSerial->begin(baud); 2026 | } 2027 | #endif 2028 | delay(100); 2029 | } 2030 | 2031 | void LTE_Shield::setTimeout(unsigned long timeout) 2032 | { 2033 | if (_hardSerial != NULL) 2034 | { 2035 | _hardSerial->setTimeout(timeout); 2036 | } 2037 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 2038 | else if (_softSerial != NULL) 2039 | { 2040 | _softSerial->setTimeout(timeout); 2041 | } 2042 | #endif 2043 | } 2044 | 2045 | bool LTE_Shield::find(char *target) 2046 | { 2047 | bool found = false; 2048 | if (_hardSerial != NULL) 2049 | { 2050 | found = _hardSerial->find(target); 2051 | } 2052 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 2053 | else if (_softSerial != NULL) 2054 | { 2055 | found = _softSerial->find(target); 2056 | } 2057 | #endif 2058 | return found; 2059 | } 2060 | 2061 | LTE_Shield_error_t LTE_Shield::autobaud(unsigned long desiredBaud) 2062 | { 2063 | LTE_Shield_error_t err = LTE_SHIELD_ERROR_INVALID; 2064 | int b = 0; 2065 | 2066 | while ((err != LTE_SHIELD_ERROR_SUCCESS) && (b < NUM_SUPPORTED_BAUD)) 2067 | { 2068 | beginSerial(LTE_SHIELD_SUPPORTED_BAUD[b++]); 2069 | setBaud(desiredBaud); 2070 | delay(200); 2071 | beginSerial(desiredBaud); 2072 | err = at(); 2073 | } 2074 | if (err == LTE_SHIELD_ERROR_SUCCESS) 2075 | { 2076 | beginSerial(desiredBaud); 2077 | } 2078 | return err; 2079 | } 2080 | 2081 | char *LTE_Shield::lte_calloc_char(size_t num) 2082 | { 2083 | return (char *)calloc(num, sizeof(char)); 2084 | } 2085 | 2086 | // GPS Helper Functions: 2087 | 2088 | // Read a source string until a delimiter is hit, store the result in destination 2089 | static char *readDataUntil(char *destination, unsigned int destSize, 2090 | char *source, char delimiter) 2091 | { 2092 | 2093 | char *strEnd; 2094 | size_t len; 2095 | 2096 | strEnd = strchr(source, delimiter); 2097 | 2098 | if (strEnd != NULL) 2099 | { 2100 | len = strEnd - source; 2101 | memset(destination, 0, destSize); 2102 | memcpy(destination, source, len); 2103 | } 2104 | 2105 | return strEnd; 2106 | } 2107 | 2108 | #define TEMP_NMEA_DATA_SIZE 16 2109 | 2110 | static boolean parseGPRMCString(char *rmcString, PositionData *pos, 2111 | ClockData *clk, SpeedData *spd) 2112 | { 2113 | char *ptr, *search; 2114 | unsigned long tTemp; 2115 | char tempData[TEMP_NMEA_DATA_SIZE]; 2116 | 2117 | // Fast-forward test to first value: 2118 | ptr = strchr(rmcString, ','); 2119 | ptr++; // Move ptr past first comma 2120 | 2121 | // If the next character is another comma, there's no time data 2122 | // Find time: 2123 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2124 | // Next comma should be present and not the next position 2125 | if ((search != NULL) && (search != ptr)) 2126 | { 2127 | pos->utc = atof(tempData); 2128 | tTemp = pos->utc; 2129 | clk->time.hour = tTemp / 10000; 2130 | tTemp -= ((unsigned long)clk->time.hour * 10000); 2131 | clk->time.minute = tTemp / 100; 2132 | tTemp -= ((unsigned long)clk->time.minute * 100); 2133 | clk->time.second = tTemp; 2134 | } 2135 | else 2136 | { 2137 | pos->utc = 0.0; 2138 | clk->time.hour = 0; 2139 | clk->time.minute = 0; 2140 | clk->time.second = 0; 2141 | } 2142 | ptr = search + 1; // Move pointer to next value 2143 | 2144 | // Find status character: 2145 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2146 | // Should be a single character 2147 | if ((search != NULL) && (search == ptr + 1)) 2148 | { 2149 | pos->status = *ptr; // Assign char at ptr to status 2150 | } 2151 | else 2152 | { 2153 | pos->status = 'X'; // Made up very bad status 2154 | } 2155 | ptr = search + 1; 2156 | 2157 | // Find latitude: 2158 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2159 | if ((search != NULL) && (search != ptr)) 2160 | { 2161 | pos->lat = atof(tempData); 2162 | } 2163 | else 2164 | { 2165 | pos->lat = 0.0; 2166 | } 2167 | ptr = search + 1; 2168 | // Find latitude hemishpere 2169 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2170 | if ((search != NULL) && (search == ptr + 1)) 2171 | { 2172 | pos->latDir = *ptr; // Assign char at ptr to status 2173 | } 2174 | else 2175 | { 2176 | pos->latDir = 'X'; 2177 | } 2178 | ptr = search + 1; 2179 | 2180 | // Find longitude: 2181 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2182 | if ((search != NULL) && (search != ptr)) 2183 | { 2184 | pos->lon = atof(tempData); 2185 | } 2186 | else 2187 | { 2188 | pos->lon = 0.0; 2189 | } 2190 | ptr = search + 1; 2191 | // Find latitude hemishpere 2192 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2193 | if ((search != NULL) && (search == ptr + 1)) 2194 | { 2195 | pos->lonDir = *ptr; // Assign char at ptr to status 2196 | } 2197 | else 2198 | { 2199 | pos->lonDir = 'X'; 2200 | } 2201 | ptr = search + 1; 2202 | 2203 | // Find speed 2204 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2205 | if ((search != NULL) && (search != ptr)) 2206 | { 2207 | spd->speed = atof(tempData); 2208 | } 2209 | else 2210 | { 2211 | spd->speed = 0.0; 2212 | } 2213 | ptr = search + 1; 2214 | // Find track 2215 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2216 | if ((search != NULL) && (search != ptr)) 2217 | { 2218 | spd->track = atof(tempData); 2219 | } 2220 | else 2221 | { 2222 | spd->track = 0.0; 2223 | } 2224 | ptr = search + 1; 2225 | 2226 | // Find date 2227 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2228 | if ((search != NULL) && (search != ptr)) 2229 | { 2230 | tTemp = atol(tempData); 2231 | clk->date.day = tTemp / 10000; 2232 | tTemp -= ((unsigned long)clk->date.day * 10000); 2233 | clk->date.month = tTemp / 100; 2234 | tTemp -= ((unsigned long)clk->date.month * 100); 2235 | clk->date.year = tTemp; 2236 | } 2237 | else 2238 | { 2239 | clk->date.day = 0; 2240 | clk->date.month = 0; 2241 | clk->date.year = 0; 2242 | } 2243 | ptr = search + 1; 2244 | 2245 | // Find magnetic variation in degrees: 2246 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2247 | if ((search != NULL) && (search != ptr)) 2248 | { 2249 | spd->magVar = atof(tempData); 2250 | } 2251 | else 2252 | { 2253 | spd->magVar = 0.0; 2254 | } 2255 | ptr = search + 1; 2256 | // Find magnetic variation direction 2257 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); 2258 | if ((search != NULL) && (search == ptr + 1)) 2259 | { 2260 | spd->magVarDir = *ptr; // Assign char at ptr to status 2261 | } 2262 | else 2263 | { 2264 | spd->magVarDir = 'X'; 2265 | } 2266 | ptr = search + 1; 2267 | 2268 | // Find position system mode 2269 | search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, '*'); 2270 | if ((search != NULL) && (search = ptr + 1)) 2271 | { 2272 | pos->mode = *ptr; 2273 | } 2274 | else 2275 | { 2276 | pos->mode = 'X'; 2277 | } 2278 | ptr = search + 1; 2279 | 2280 | if (pos->status == 'A') 2281 | { 2282 | return true; 2283 | } 2284 | return false; 2285 | } 2286 | -------------------------------------------------------------------------------- /src/SparkFun_LTE_Shield_Arduino_Library.h: -------------------------------------------------------------------------------- 1 | /* 2 | Arduino Library for the SparkFun LTE CAT M1/NB-IoT Shield - SARA-R4 3 | 4 | SparkFun sells these at its website: www.sparkfun.com 5 | Do you like this library? Help support SparkFun. Buy a board! 6 | https://www.sparkfun.com/products/14997 7 | Written by Jim Lindblom @ SparkFun Electronics, September 5, 2018 8 | 9 | This Arduino library provides mechanisms to initialize and use 10 | the SARA-R4 module over either a SoftwareSerial or hardware serial port. 11 | 12 | Supported features include: 13 | * Network registration -- Register your shield on a MNO 14 | * SMS messaging -- Send an SMS message 15 | * TCP/IP Messaging -- Sending data to servers or setting the SARA 16 | module up as a listening socket. 17 | * u-blox GPS module support -- Plug in a u-blox GPS module via 18 | I2C to read it's location data. 19 | 20 | Development environment specifics: 21 | Arduino IDE 1.8.5 22 | This program is distributed in the hope that it will be useful, 23 | but WITHOUT ANY WARRANTY; without even the implied warranty of 24 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 25 | GNU General Public License for more details. 26 | You should have received a copy of the GNU General Public License 27 | along with this program. If not, see . 28 | */ 29 | 30 | #ifndef SPARKFUN_LTE_SHIELD_ARDUINO_LIBRARY_H 31 | #define SPARKFUN_LTE_SHIELD_ARDUINO_LIBRARY_H 32 | 33 | #if (ARDUINO >= 100) 34 | #include "Arduino.h" 35 | #else 36 | #include "WProgram.h" 37 | #endif 38 | 39 | #ifdef ARDUINO_ARCH_AVR // Arduino AVR boards (Uno, Pro Micro, etc.) 40 | #define LTE_SHIELD_SOFTWARE_SERIAL_ENABLED // Enable software serial 41 | #endif 42 | 43 | #ifdef ARDUINO_ARCH_SAMD // Arduino SAMD boards (SAMD21, etc.) 44 | #define LTE_SHIELD_SOFTWARE_SERIAL_ENABLEDx // Disable software serial 45 | #endif 46 | 47 | #ifdef ARDUINO_ARCH_APOLLO3 // Arduino Apollo boards (Artemis module, RedBoard Artemis, etc) 48 | #define LTE_SHIELD_SOFTWARE_SERIAL_ENABLED // Enable software serial 49 | #endif 50 | 51 | #ifdef ARDUINO_ARCH_STM32 // STM32 based boards (Disco, Nucleo, etc) 52 | #define LTE_SHIELD_SOFTWARE_SERIAL_ENABLED // Enable software serial 53 | #endif 54 | 55 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 56 | #include 57 | #endif 58 | 59 | #include 60 | 61 | #define LTE_SHIELD_POWER_PIN 5 62 | #define LTE_SHIELD_RESET_PIN 6 63 | 64 | typedef enum 65 | { 66 | MNO_INVALID = -1, 67 | MNO_SW_DEFAULT = 0, 68 | MNO_SIM_ICCD = 1, 69 | MNO_ATT = 2, 70 | MNO_VERIZON = 3, 71 | MNO_TELSTRA = 4, 72 | MNO_TMO = 5, 73 | MNO_CT = 6 74 | } mobile_network_operator_t; 75 | 76 | typedef enum 77 | { 78 | LTE_SHIELD_ERROR_INVALID = -1, // -1 79 | LTE_SHIELD_ERROR_SUCCESS = 0, // 0 80 | LTE_SHIELD_ERROR_OUT_OF_MEMORY, // 1 81 | LTE_SHIELD_ERROR_TIMEOUT, // 2 82 | LTE_SHIELD_ERROR_UNEXPECTED_PARAM, // 3 83 | LTE_SHIELD_ERROR_UNEXPECTED_RESPONSE, // 4 84 | LTE_SHIELD_ERROR_NO_RESPONSE, // 5 85 | LTE_SHIELD_ERROR_DEREGISTERED // 6 86 | } LTE_Shield_error_t; 87 | #define LTE_SHIELD_SUCCESS LTE_SHIELD_ERROR_SUCCESS 88 | 89 | typedef enum 90 | { 91 | LTE_SHIELD_REGISTRATION_INVALID = -1, 92 | LTE_SHIELD_REGISTRATION_NOT_REGISTERED = 0, 93 | LTE_SHIELD_REGISTRATION_HOME = 1, 94 | LTE_SHIELD_REGISTRATION_SEARCHING = 2, 95 | LTE_SHIELD_REGISTRATION_DENIED = 3, 96 | LTE_SHIELD_REGISTRATION_UNKNOWN = 4, 97 | LTE_SHIELD_REGISTRATION_ROAMING = 5, 98 | LTE_SHIELD_REGISTRATION_HOME_SMS_ONLY = 6, 99 | LTE_SHIELD_REGISTRATION_ROAMING_SMS_ONLY = 7, 100 | LTE_SHIELD_REGISTRATION_HOME_CSFB_NOT_PREFERRED = 8, 101 | LTE_SHIELD_REGISTRATION_ROAMING_CSFB_NOT_PREFERRED = 9 102 | } LTE_Shield_registration_status_t; 103 | 104 | struct DateData 105 | { 106 | uint8_t day; 107 | uint8_t month; 108 | unsigned int year; 109 | }; 110 | 111 | struct TimeData 112 | { 113 | uint8_t hour; 114 | uint8_t minute; 115 | uint8_t second; 116 | unsigned int ms; 117 | uint8_t tzh; 118 | uint8_t tzm; 119 | }; 120 | 121 | struct ClockData 122 | { 123 | struct DateData date; 124 | struct TimeData time; 125 | }; 126 | 127 | struct PositionData 128 | { 129 | float utc; 130 | float lat; 131 | char latDir; 132 | float lon; 133 | char lonDir; 134 | float alt; 135 | char mode; 136 | char status; 137 | }; 138 | 139 | struct SpeedData 140 | { 141 | float speed; 142 | float track; 143 | float magVar; 144 | char magVarDir; 145 | }; 146 | 147 | struct operator_stats 148 | { 149 | uint8_t stat; 150 | String shortOp; 151 | String longOp; 152 | unsigned long numOp; 153 | uint8_t act; 154 | }; 155 | 156 | typedef enum 157 | { 158 | LTE_SHIELD_TCP = 6, 159 | LTE_SHIELD_UDP = 17 160 | } lte_shield_socket_protocol_t; 161 | 162 | typedef enum 163 | { 164 | LTE_SHIELD_MESSAGE_FORMAT_PDU = 0, 165 | LTE_SHIELD_MESSAGE_FORMAT_TEXT = 1 166 | } lte_shield_message_format_t; 167 | 168 | class LTE_Shield : public Print 169 | { 170 | public: 171 | // Constructor 172 | LTE_Shield(uint8_t powerPin = LTE_SHIELD_POWER_PIN, uint8_t resetPin = LTE_SHIELD_RESET_PIN); 173 | 174 | // Begin -- initialize BT module and ensure it's connected 175 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 176 | boolean begin(SoftwareSerial &softSerial, unsigned long baud = 9600); 177 | #endif 178 | boolean begin(HardwareSerial &hardSerial, unsigned long baud = 9600); 179 | 180 | // Loop polling and polling setup 181 | boolean poll(void); 182 | void setSocketReadCallback(void (*socketReadCallback)(int, String)); 183 | void setSocketCloseCallback(void (*socketCloseCallback)(int)); 184 | void setGpsReadCallback(void (*gpsRequestCallback)(ClockData time, 185 | PositionData gps, SpeedData spd, unsigned long uncertainty)); 186 | 187 | // Direct write/print to cell serial port 188 | virtual size_t write(uint8_t c); 189 | virtual size_t write(const char *str); 190 | virtual size_t write(const char *buffer, size_t size); 191 | 192 | // General AT Commands 193 | LTE_Shield_error_t at(void); 194 | LTE_Shield_error_t enableEcho(boolean enable = true); 195 | String imei(void); 196 | String imsi(void); 197 | String ccid(void); 198 | 199 | // Control and status AT commands 200 | LTE_Shield_error_t reset(void); 201 | String clock(void); 202 | // TODO: Return a clock struct 203 | LTE_Shield_error_t clock(uint8_t *y, uint8_t *mo, uint8_t *d, 204 | uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz); 205 | LTE_Shield_error_t autoTimeZone(boolean enable); 206 | 207 | // Network service AT commands 208 | int8_t rssi(void); 209 | LTE_Shield_registration_status_t registration(void); 210 | boolean setNetwork(mobile_network_operator_t mno); 211 | mobile_network_operator_t getNetwork(void); 212 | typedef enum 213 | { 214 | PDP_TYPE_INVALID = -1, 215 | PDP_TYPE_IP = 0, 216 | PDP_TYPE_NONIP = 1, 217 | PDP_TYPE_IPV4V6 = 2, 218 | PDP_TYPE_IPV6 = 3 219 | } LTE_Shield_pdp_type; 220 | LTE_Shield_error_t setAPN(String apn, uint8_t cid = 1, LTE_Shield_pdp_type pdpType = PDP_TYPE_IP); 221 | LTE_Shield_error_t getAPN(String *apn, IPAddress *ip); 222 | 223 | typedef enum 224 | { 225 | L2P_DEFAULT, 226 | L2P_PPP, 227 | L2P_M_HEX, 228 | L2P_M_RAW_IP, 229 | L2P_M_OPT_PPP 230 | } LTE_Shield_l2p_t; 231 | LTE_Shield_error_t enterPPP(uint8_t cid = 1, char dialing_type_char = 0, 232 | unsigned long dialNumber = 99, LTE_Shield_l2p_t l2p = L2P_DEFAULT); 233 | 234 | uint8_t getOperators(struct operator_stats *op, int maxOps = 3); 235 | LTE_Shield_error_t registerOperator(struct operator_stats oper); 236 | LTE_Shield_error_t getOperator(String *oper); 237 | LTE_Shield_error_t deregisterOperator(void); 238 | 239 | // SMS -- Short Messages Service 240 | LTE_Shield_error_t setSMSMessageFormat(lte_shield_message_format_t textMode = LTE_SHIELD_MESSAGE_FORMAT_TEXT); 241 | LTE_Shield_error_t sendSMS(String number, String message); 242 | 243 | // V24 Control and V25ter (UART interface) AT commands 244 | LTE_Shield_error_t setBaud(unsigned long baud); 245 | 246 | // GPIO 247 | // GPIO pin map 248 | typedef enum 249 | { 250 | GPIO1 = 16, 251 | GPIO2 = 23, 252 | GPIO3 = 24, 253 | GPIO4 = 25, 254 | GPIO5 = 42, 255 | GPIO6 = 19 256 | } LTE_Shield_gpio_t; 257 | // GPIO pin modes 258 | typedef enum 259 | { 260 | GPIO_MODE_INVALID = -1, 261 | GPIO_OUTPUT = 0, 262 | GPIO_INPUT, 263 | NETWORK_STATUS, 264 | GNSS_SUPPLY_ENABLE, 265 | GNSS_DATA_READY, 266 | GNSS_RTC_SHARING, 267 | SIM_CARD_DETECTION, 268 | HEADSET_DETECTION, 269 | GSM_TX_BURST_INDICATION, 270 | MODULE_OPERATING_STATUS_INDICATION, 271 | MODULE_FUNCTIONALITY_STATUS_INDICATION, 272 | I2S_DIGITAL_AUDIO_INTERFACE, 273 | SPI_SERIAL_INTERFACE, 274 | MASTER_CLOCK_GENRATION, 275 | UART_INTERFACE, 276 | WIFI_ENABLE, 277 | RING_INDICATION, 278 | LAST_GASP_ENABLE, 279 | PAD_DISABLED = 255 280 | } LTE_Shield_gpio_mode_t; 281 | LTE_Shield_error_t setGpioMode(LTE_Shield_gpio_t gpio, LTE_Shield_gpio_mode_t mode); 282 | LTE_Shield_gpio_mode_t getGpioMode(LTE_Shield_gpio_t gpio); 283 | 284 | // IP Transport Layer 285 | int socketOpen(lte_shield_socket_protocol_t protocol, unsigned int localPort = 0); 286 | LTE_Shield_error_t socketClose(int socket, int timeout = 1000); 287 | LTE_Shield_error_t socketConnect(int socket, const char *address, unsigned int port); 288 | LTE_Shield_error_t socketWrite(int socket, const char *str); 289 | LTE_Shield_error_t socketWrite(int socket, String str); 290 | LTE_Shield_error_t socketRead(int socket, int length, char *readDest); 291 | LTE_Shield_error_t socketListen(int socket, unsigned int port); 292 | IPAddress lastRemoteIP(void); 293 | 294 | // GPS 295 | typedef enum 296 | { 297 | GNSS_SYSTEM_GPS = 1, 298 | GNSS_SYSTEM_SBAS = 2, 299 | GNSS_SYSTEM_GALILEO = 4, 300 | GNSS_SYSTEM_BEIDOU = 8, 301 | GNSS_SYSTEM_IMES = 16, 302 | GNSS_SYSTEM_QZSS = 32, 303 | GNSS_SYSTEM_GLONASS = 64 304 | } gnss_system_t; 305 | boolean gpsOn(void); 306 | LTE_Shield_error_t gpsPower(boolean enable = true, 307 | gnss_system_t gnss_sys = GNSS_SYSTEM_GPS); 308 | LTE_Shield_error_t gpsEnableClock(boolean enable = true); 309 | LTE_Shield_error_t gpsGetClock(struct ClockData *clock); 310 | LTE_Shield_error_t gpsEnableFix(boolean enable = true); 311 | LTE_Shield_error_t gpsGetFix(float *lat, float *lon, 312 | unsigned int *alt, uint8_t *quality, uint8_t *sat); 313 | LTE_Shield_error_t gpsGetFix(struct PositionData *pos); 314 | LTE_Shield_error_t gpsEnablePos(boolean enable = true); 315 | LTE_Shield_error_t gpsGetPos(struct PositionData *pos); 316 | LTE_Shield_error_t gpsEnableSat(boolean enable = true); 317 | LTE_Shield_error_t gpsGetSat(uint8_t *sats); 318 | LTE_Shield_error_t gpsEnableRmc(boolean enable = true); 319 | LTE_Shield_error_t gpsGetRmc(struct PositionData *pos, struct SpeedData *speed, 320 | struct ClockData *clk, boolean *valid); 321 | LTE_Shield_error_t gpsEnableSpeed(boolean enable = true); 322 | LTE_Shield_error_t gpsGetSpeed(struct SpeedData *speed); 323 | 324 | LTE_Shield_error_t gpsRequest(unsigned int timeout, uint32_t accuracy, boolean detailed = true); 325 | 326 | private: 327 | HardwareSerial *_hardSerial; 328 | #ifdef LTE_SHIELD_SOFTWARE_SERIAL_ENABLED 329 | SoftwareSerial *_softSerial; 330 | #endif 331 | 332 | uint8_t _powerPin; 333 | uint8_t _resetPin; 334 | unsigned long _baud; 335 | IPAddress _lastRemoteIP; 336 | IPAddress _lastLocalIP; 337 | 338 | void (*_socketReadCallback)(int, String); 339 | void (*_socketCloseCallback)(int); 340 | void (*_gpsRequestCallback)(ClockData, PositionData, SpeedData, unsigned long); 341 | 342 | typedef enum 343 | { 344 | LTE_SHIELD_INIT_STANDARD, 345 | LTE_SHIELD_INIT_AUTOBAUD, 346 | LTE_SHIELD_INIT_RESET 347 | } LTE_Shield_init_type_t; 348 | 349 | typedef enum 350 | { 351 | MINIMUM_FUNCTIONALITY = 0, 352 | FULL_FUNCTIONALITY = 1, 353 | SILENT_RESET = 15, 354 | SILENT_RESET_W_SIM = 16 355 | } LTE_Shield_functionality_t; 356 | 357 | LTE_Shield_error_t init(unsigned long baud, LTE_Shield_init_type_t initType = LTE_SHIELD_INIT_STANDARD); 358 | 359 | void powerOn(void); 360 | 361 | void hwReset(void); 362 | 363 | LTE_Shield_error_t functionality(LTE_Shield_functionality_t function = FULL_FUNCTIONALITY); 364 | 365 | LTE_Shield_error_t setMno(mobile_network_operator_t mno); 366 | LTE_Shield_error_t getMno(mobile_network_operator_t *mno); 367 | 368 | // Wait for an expected response (don't send a command) 369 | LTE_Shield_error_t waitForResponse(const char *expectedResponse, uint16_t timeout); 370 | 371 | // Send command with an expected (potentially partial) response, store entire response 372 | LTE_Shield_error_t sendCommandWithResponse(const char *command, const char *expectedResponse, 373 | char *responseDest, unsigned long commandTimeout, boolean at = true); 374 | 375 | // Send a command -- prepend AT if at is true 376 | boolean sendCommand(const char *command, boolean at); 377 | 378 | LTE_Shield_error_t parseSocketReadIndication(int socket, int length); 379 | LTE_Shield_error_t parseSocketListenIndication(IPAddress localIP, IPAddress remoteIP); 380 | LTE_Shield_error_t parseSocketCloseIndication(String *closeIndication); 381 | 382 | // UART Functions 383 | size_t hwPrint(const char *s); 384 | size_t hwWrite(const char c); 385 | int readAvailable(char *inString); 386 | char readChar(void); 387 | int hwAvailable(void); 388 | void beginSerial(unsigned long baud); 389 | void setTimeout(unsigned long timeout); 390 | bool find(char *target); 391 | 392 | LTE_Shield_error_t autobaud(unsigned long desiredBaud); 393 | 394 | char *lte_calloc_char(size_t num); 395 | }; 396 | 397 | #endif //SPARKFUN_LTE_SHIELD_ARDUINO_LIBRARY_H --------------------------------------------------------------------------------