diff --git a/examples/SARA-R5_Example10_SocketPingPong/SARA-R5_Example10_SocketPingPong.ino b/examples/SARA-R5_Example10_SocketPingPong/SARA-R5_Example10_SocketPingPong.ino new file mode 100644 index 0000000..5eb05b4 --- /dev/null +++ b/examples/SARA-R5_Example10_SocketPingPong/SARA-R5_Example10_SocketPingPong.ino @@ -0,0 +1,545 @@ +/* + + SARA-R5 Example + =============== + + Socket "Ping Pong" - TCP Data Transfers + + Written by: Paul Clark + Date: December 30th 2021 + + This example demonstrates how to transfer data from one SARA-R5 to another using TCP sockets. + + This example includes the code from Example7_ConfigurePacketSwitchedData to let you see the SARA-R5's IP address. + If you select "Ping": + The code asks for the IP Address of the "Pong" SARA-R5 + The code then opens a TCP socket to the "Pong" SARA-R5 using port number TCP_PORT + The code sends an initial "Ping" using Write Socket Data (+USOWR) + The code polls continuously. When a +UUSORD URC message is received, data is read and passed to the socketReadCallback. + When "Pong" is received by the callback, the code sends "Ping" in reply + The Ping-Pong repeats 100 times + The socket is closed after the 100th Ping is sent + If you select "Pong": + The code opens a TCP socket and waits for a connection and for data to arrive + The code polls continuously. When a +UUSORD URC message is received, data is read and passed to the socketReadCallback. + When "Ping" is received by the callback, the code sends "Pong" in reply + The socket is closed after 120 seconds + Start the "Pong" first! + + You may find that your service provider is blocking incoming TCP connections to the SARA-R5, preventing the "Pong" from working... + If that is the case, you can use this code to play ping-pong with another computer acting as a TCP Echo Server. + Here's a quick how-to (assuming you are familiar with Python): + Open up a Python editor on your computer + Grab yourself some simple TCP Echo Server code: + The third example here works well: https://rosettacode.org/wiki/Echo_server#Python + Log in to your router + Find your local IP address (usually 192.168.0.something) + Go into your router's Security / Port Forwarding settings: + Create a new port forwarding rule + The IP address is your local IP address + Set the local port range to 1200-1200 (if you changed TCP_PORT, use that port number instead) + Set the external port range to 1200-1200 + Set the protocol to TCP + Enable the rule + This will open up a direct connection from the outside world, through your router, to port 1200 on your computer + Remember to lock it down again when you're done! + Edit the Python code and replace 'localhost' with your local IP number: + HOST = '192.168.0.nnn' + Change the PORT to 1200: + PORT = 1200 + Run the Python code + Ask Google for your computer's public IP address: + Google "what is my IP address" + Run this code and choose the "Ping" option + Enter your computer's public IP address when asked + Sit back and watch the ping-pong! + The code will stop after 100 Pings+Echos and 100 Pongs+Echos + That's 400 TCP transfers in total! + + Feel like supporting open source hardware? + Buy a board from SparkFun! + + Licence: MIT + Please see LICENSE.md for full details + +*/ + +#include //Click here to get the library: http://librarymanager/All#SparkFun_u-blox_SARA-R5_Arduino_Library + +// Uncomment the next line to connect to the SARA-R5 using hardware Serial1 +#define saraSerial Serial1 + +// Uncomment the next line to create a SoftwareSerial object to pass to the SARA-R5 library instead +//SoftwareSerial saraSerial(8, 9); + +// Create a SARA_R5 object to use throughout the sketch +// Usually we would tell the library which GPIO pin to use to control the SARA power (see below), +// but we can start the SARA without a power pin. It just means we need to manually +// turn the power on if required! ;-D +SARA_R5 mySARA; + +// Create a SARA_R5 object to use throughout the sketch +// We need to tell the library what GPIO pin is connected to the SARA power pin. +// If you're using the MicroMod Asset Tracker and the MicroMod Artemis Processor Board, +// the pin name is G2 which is connected to pin AD34. +// Change the pin number if required. +//SARA_R5 mySARA(34); + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +unsigned int TCP_PORT = 1200; // Change this if required + +bool iAmPing; + +// Keep track of how many ping-pong exchanges have taken place. "Ping" closes the socket when pingCount reaches pingPongLimit. +volatile int pingCount = 0; +volatile int pongCount = 0; +const int pingPongLimit = 100; + +// Keep track of how long the socket has been open. "Pong" closes the socket when timeLimit (millis) is reached. +unsigned long startTime; +const unsigned long timeLimit = 120000; // 120 seconds + +#include // Needed for sockets +volatile int socketNum; + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// processSocketListen is provided to the SARA-R5 library via a +// callback setter -- setSocketListenCallback. (See setup()) +void processSocketListen(int listeningSocket, IPAddress localIP, unsigned int listeningPort, int socket, IPAddress remoteIP, unsigned int port) +{ + Serial.println(); + Serial.print(F("Socket connection made: listeningSocket ")); + Serial.print(listeningSocket); + Serial.print(F(" localIP ")); + Serial.print(localIP[0]); + Serial.print(F(".")); + Serial.print(localIP[1]); + Serial.print(F(".")); + Serial.print(localIP[2]); + Serial.print(F(".")); + Serial.print(localIP[3]); + Serial.print(F(" listeningPort ")); + Serial.print(listeningPort); + Serial.print(F(" socket ")); + Serial.print(socket); + Serial.print(F(" remoteIP ")); + Serial.print(remoteIP[0]); + Serial.print(F(".")); + Serial.print(remoteIP[1]); + Serial.print(F(".")); + Serial.print(remoteIP[2]); + Serial.print(F(".")); + Serial.print(remoteIP[3]); + Serial.print(F(" port ")); + Serial.println(port); +} + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// processSocketData is provided to the SARA-R5 library via a +// callback setter -- setSocketReadCallback. (See setup()) +void processSocketData(int socket, String theData) +{ + Serial.println(); + Serial.print(F("Data received on socket ")); + Serial.print(socket); + Serial.print(F(" : ")); + Serial.println(theData); + + if (theData == String("Ping")) // Look for the "Ping" + { + const char pong[] = "Pong"; + mySARA.socketWrite(socket, pong); // Send the "Pong" + pongCount++; + } + + if (theData == String("Pong")) // Look for the "Pong" + { + const char ping[] = "Ping"; + mySARA.socketWrite(socket, ping); // Send the "Ping" + pingCount++; + } + + Serial.print(F("pingCount = ")); + Serial.print(pingCount); + Serial.print(F(" : pongCount = ")); + Serial.println(pongCount); +} + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// processSocketClose is provided to the SARA-R5 library via a +// callback setter -- setSocketCloseCallback. (See setup()) +void processSocketClose(int socket) +{ + Serial.println(); + Serial.print(F("Socket ")); + Serial.print(socket); + Serial.println(F(" closed!")); +} + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +// processPSDAction is provided to the SARA-R5 library via a +// callback setter -- setPSDActionCallback. (See setup()) +void processPSDAction(int result, IPAddress ip) +{ + Serial.println(); + Serial.print(F("PSD Action: result: ")); + Serial.print(String(result)); + if (result == 0) + Serial.print(F(" (success)")); + Serial.print(F(" IP Address: \"")); + Serial.print(String(ip[0])); + Serial.print(F(".")); + Serial.print(String(ip[1])); + Serial.print(F(".")); + Serial.print(String(ip[2])); + Serial.print(F(".")); + Serial.print(String(ip[3])); + Serial.println(F("\"")); +} + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + +void setup() +{ + String currentOperator = ""; + + Serial.begin(115200); // Start the serial console + + // Wait for user to press key to begin + Serial.println(F("SARA-R5 Example")); + Serial.println(F("Press any key to begin")); + + while (!Serial.available()) // Wait for the user to press a key (send any serial character) + ; + while (Serial.available()) // Empty the serial RX buffer + Serial.read(); + + //mySARA.enableDebugging(); // Uncomment this line to enable helpful debug messages on Serial + + // For the MicroMod Asset Tracker, we need to invert the power pin so it pulls high instead of low + // Comment the next line if required + mySARA.invertPowerPin(true); + + // Initialize the SARA + if (mySARA.begin(saraSerial, 9600) ) + { + Serial.println(F("SARA-R5 connected!")); + } + else + { + Serial.println(F("Unable to communicate with the SARA.")); + Serial.println(F("Manually power-on (hold the SARA On button for 3 seconds) on and try again.")); + while (1) ; // Loop forever on fail + } + Serial.println(); + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + // First check to see if we're connected to an operator: + if (mySARA.getOperator(¤tOperator) == SARA_R5_SUCCESS) + { + Serial.print(F("Connected to: ")); + Serial.println(currentOperator); + } + else + { + Serial.print(F("The SARA is not yet connected to an operator. Please use the previous examples to connect. Or wait and retry. Freezing...")); + while (1) + ; // Do nothing more + } + + int minCID = SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS; // Keep a record of the highest and lowest CIDs + int maxCID = 0; + + Serial.println(F("The available Context IDs are:")); + Serial.println(F("Context ID:\tAPN Name:\tIP Address:")); + for (int cid = 0; cid < SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS; cid++) + { + String apn = ""; + IPAddress ip(0, 0, 0, 0); + mySARA.getAPN(cid, &apn, &ip); + if (apn.length() > 0) + { + Serial.print(cid); + Serial.print(F("\t")); + Serial.print(apn); + Serial.print(F("\t")); + Serial.println(ip); + } + if (cid < minCID) + minCID = cid; // Record the lowest CID + if (cid > maxCID) + maxCID = cid; // Record the highest CID + } + Serial.println(); + + Serial.println(F("Which Context ID do you want to use for your Packet Switched Data connection?")); + Serial.println(F("Please enter the number (followed by LF / Newline): ")); + + char c = 0; + bool selected = false; + int selection = 0; + while (!selected) + { + while (!Serial.available()) ; // Wait for a character to arrive + c = Serial.read(); // Read it + if (c == '\n') // Is it a LF? + { + if ((selection >= minCID) && (selection <= maxCID)) + { + selected = true; + Serial.println("Using CID: " + String(selection)); + } + else + { + Serial.println(F("Invalid CID. Please try again:")); + selection = 0; + } + } + else + { + selection *= 10; // Multiply selection by 10 + selection += c - '0'; // Add the new digit to selection + } + } + + // Deactivate the profile + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_DEACTIVATE) != SARA_R5_SUCCESS) + { + Serial.println(F("Warning: performPDPaction (deactivate profile) failed. Probably because no profile was active.")); + } + + // Map PSD profile 0 to the selected CID + if (mySARA.setPDPconfiguration(0, SARA_R5_PSD_CONFIG_PARAM_MAP_TO_CID, selection) != SARA_R5_SUCCESS) + { + Serial.println(F("setPDPconfiguration (map to CID) failed! Freezing...")); + while (1) + ; // Do nothing more + } + + // Set the protocol type - this needs to match the defined IP type for the CID (as opposed to what was granted by the network) + if (mySARA.setPDPconfiguration(0, SARA_R5_PSD_CONFIG_PARAM_PROTOCOL, SARA_R5_PSD_PROTOCOL_IPV4V6_V4_PREF) != SARA_R5_SUCCESS) + // You _may_ need to change the protocol type: ----------------------------------------^ + { + Serial.println(F("setPDPconfiguration (set protocol type) failed! Freezing...")); + while (1) + ; // Do nothing more + } + + // Set a callback to process the results of the PSD Action + mySARA.setPSDActionCallback(&processPSDAction); + + // Activate the profile + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_ACTIVATE) != SARA_R5_SUCCESS) + { + Serial.println(F("performPDPaction (activate profile) failed! Freezing...")); + while (1) + ; // Do nothing more + } + + for (int i = 0; i < 100; i++) // Wait for up to a second for the PSD Action URC to arrive + { + mySARA.bufferedPoll(); // Keep processing data from the SARA so we can process the PSD Action + delay(10); + } + + // Save the profile to NVM - so we can load it again in the later examples + if (mySARA.performPDPaction(0, SARA_R5_PSD_ACTION_STORE) != SARA_R5_SUCCESS) + { + Serial.println(F("performPDPaction (save to NVM) failed! Freezing...")); + while (1) + ; // Do nothing more + } + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + // Set a callback to process the socket listen + mySARA.setSocketListenCallback(&processSocketListen); + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + // Set a callback to process the socket data + mySARA.setSocketReadCallback(&processSocketData); + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + // Set a callback to process the socket close + mySARA.setSocketCloseCallback(&processSocketClose); + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + Serial.println(F("\r\nDo you want to Ping or Pong? (Always start the Pong first!)\r\n")); + Serial.println(F("1: Ping")); + Serial.println(F("2: Pong")); + Serial.println(F("\r\nPlease enter the number (followed by LF / Newline): ")); + + c = 0; + selected = false; + selection = 0; + while (!selected) + { + while (!Serial.available()) ; // Wait for a character to arrive + c = Serial.read(); // Read it + if (c == '\n') // Is it a LF? + { + if ((selection >= 1) && (selection <= 2)) + { + selected = true; + if (selection == 1) + Serial.println(F("\r\nPing selected!")); + else + Serial.println(F("\r\nPong selected!")); + } + else + { + Serial.println(F("Invalid choice. Please try again:")); + selection = 0; + } + } + else + { + selection = c - '0'; // Store a single digit + } + } + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + if (selection == 1) // Ping + { + iAmPing = true; + + Serial.println(F("\r\nPlease enter the IP number you want to ping (nnn.nnn.nnn.nnn followed by LF / Newline): ")); + + char c = 0; + bool selected = false; + int val = 0; + IPAddress theAddress = {0,0,0,0}; + int field = 0; + while (!selected) + { + while (!Serial.available()) ; // Wait for a character to arrive + c = Serial.read(); // Read it + if (c == '\n') // Is it a LF? + { + theAddress[field] = val; // Store the current value + if (field == 3) + selected = true; + else + { + Serial.println(F("Invalid IP Address. Please try again:")); + val = 0; + field = 0; + } + } + else if (c == '.') // Is it a separator + { + theAddress[field] = val; // Store the current value + if (field <= 2) + field++; // Increment the field + val = 0; // Reset the value + } + else + { + val *= 10; // Multiply by 10 + val += c - '0'; // Add the digit + } + } + + char theAddressString[16]; + sprintf(theAddressString, "%d.%d.%d.%d", theAddress[0], theAddress[1], theAddress[2], theAddress[3]); + Serial.print(F("Remote address is ")); + Serial.println(theAddressString); + + // Open the socket + socketNum = mySARA.socketOpen(SARA_R5_TCP); + if (socketNum == -1) + { + Serial.println(F("socketOpen failed! Freezing...")); + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + + Serial.print(F("Using socket ")); + Serial.println(socketNum); + + // Connect to the remote IP Address + if (mySARA.socketConnect(socketNum, (const char *)theAddressString, TCP_PORT) != SARA_R5_SUCCESS) + { + Serial.println(F("socketConnect failed! Freezing...")); + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + else + { + Serial.println(F("Socket connected!")); + } + + // Send the first ping to start the ping-pong + const char ping[] = "Ping"; + mySARA.socketWrite(socketNum, ping); // Send the "Ping" + + } + + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + else // if (selection == 2) // Pong + { + iAmPing = false; + + // Open the socket + socketNum = mySARA.socketOpen(SARA_R5_TCP); + if (socketNum == -1) + { + Serial.println(F("socketOpen failed! Freezing...")); + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + + Serial.print(F("Using socket ")); + Serial.println(socketNum); + + // Start listening for a connection + if (mySARA.socketListen(socketNum, TCP_PORT) != SARA_R5_SUCCESS) + { + Serial.println(F("socketListen failed! Freezing...")); + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + } + +// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- + + startTime = millis(); // Record that start time + +} + +void loop() +{ + mySARA.bufferedPoll(); // Process the backlog (if any) and any fresh serial data + + if (iAmPing) // Ping - close the socket when we've reached pingPongLimit + { + if (pingCount >= pingPongLimit) + { + mySARA.socketClose(socketNum); // Close the socket - no more pings will be sent + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + } + + else // Pong - close the socket when we've reached the timeLimit + { + if (millis() > (startTime + timeLimit)) + { + mySARA.socketClose(socketNum); // Close the socket - no more pongs will be sent + while (1) + mySARA.bufferedPoll(); // Do nothing more except process any received data + } + } +} diff --git a/keywords.txt b/keywords.txt index b462036..87e1598 100644 --- a/keywords.txt +++ b/keywords.txt @@ -44,9 +44,12 @@ gnss_aiding_mode_t KEYWORD1 begin KEYWORD2 enableDebugging KEYWORD2 invertPowerPin KEYWORD2 +modulePowerOff KEYWORD2 +modulePowerOn KEYWORD2 bufferedPoll KEYWORD2 processReadEvent KEYWORD2 poll KEYWORD2 +setSocketListenCallback KEYWORD2 setSocketReadCallback KEYWORD2 setSocketCloseCallback KEYWORD2 setGpsReadCallback KEYWORD2 diff --git a/library.properties b/library.properties index 41bbd7d..16315c8 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=SparkFun u-blox SARA-R5 Arduino Library -version=1.0.2 +version=1.0.3 author=SparkFun Electronics maintainer=SparkFun Electronics sentence=Library for the u-blox SARA-R5 LTE-M / NB-IoT modules with secure cloud diff --git a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp index f76ac2c..02221ea 100644 --- a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp +++ b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.cpp @@ -19,889 +19,885 @@ SARA_R5::SARA_R5(int powerPin, int resetPin, uint8_t maxInitDepth) { #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - _softSerial = NULL; + _softSerial = NULL; #endif - _hardSerial = NULL; - _baud = 0; - _resetPin = resetPin; - _powerPin = powerPin; - _invertPowerPin = false; - _maxInitDepth = maxInitDepth; - _socketReadCallback = NULL; - _socketCloseCallback = NULL; - _gpsRequestCallback = NULL; - _simStateReportCallback = NULL; - _psdActionRequestCallback = NULL; - _pingRequestCallback = NULL; - _httpCommandRequestCallback = NULL; - _lastRemoteIP = {0, 0, 0, 0}; - _lastLocalIP = {0, 0, 0, 0}; - - memset(saraRXBuffer, 0, RXBuffSize); - memset(saraResponseBacklog, 0, RXBuffSize); + _hardSerial = NULL; + _baud = 0; + _resetPin = resetPin; + _powerPin = powerPin; + _invertPowerPin = false; + _maxInitDepth = maxInitDepth; + _socketListenCallback = NULL; + _socketReadCallback = NULL; + _socketCloseCallback = NULL; + _gpsRequestCallback = NULL; + _simStateReportCallback = NULL; + _psdActionRequestCallback = NULL; + _pingRequestCallback = NULL; + _httpCommandRequestCallback = NULL; + _lastRemoteIP = {0, 0, 0, 0}; + _lastLocalIP = {0, 0, 0, 0}; + + memset(saraRXBuffer, 0, RXBuffSize); + memset(saraResponseBacklog, 0, RXBuffSize); } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED bool SARA_R5::begin(SoftwareSerial &softSerial, unsigned long baud) { - SARA_R5_error_t err; + SARA_R5_error_t err; - _softSerial = &softSerial; + _softSerial = &softSerial; - err = init(baud); - if (err == SARA_R5_ERROR_SUCCESS) - { - return true; - } - return false; + err = init(baud); + if (err == SARA_R5_ERROR_SUCCESS) + { + return true; + } + return false; } #endif bool SARA_R5::begin(HardwareSerial &hardSerial, unsigned long baud) { - SARA_R5_error_t err; + SARA_R5_error_t err; - _hardSerial = &hardSerial; + _hardSerial = &hardSerial; - err = init(baud); - if (err == SARA_R5_ERROR_SUCCESS) - { - return true; - } - return false; + err = init(baud); + if (err == SARA_R5_ERROR_SUCCESS) + { + return true; + } + return false; } //Calling this function with nothing sets the debug port to Serial //You can also call it with other streams like Serial1, SerialUSB, etc. void SARA_R5::enableDebugging(Stream &debugPort) { - _debugPort = &debugPort; - _printDebug = true; + _debugPort = &debugPort; + _printDebug = true; } +// This function was originally written by Matthew Menze for the LTE Shield (SARA-R4) library +// See: https://github.com/sparkfun/SparkFun_LTE_Shield_Arduino_Library/pull/8 +// It does the same job as ::poll but also processed any 'old' data stored in the backlog first +// It also has a built-in timeout - which ::poll does not bool SARA_R5::bufferedPoll(void) { - int avail = 0; + int avail = 0; char c = 0; bool handled = false; - unsigned long timeIn = micros(); - memset(saraRXBuffer, 0, RXBuffSize); - int backlogLen = strlen(saraResponseBacklog); - char *event; + unsigned long timeIn = micros(); + char *event; - if (backlogLen > 0) + memset(saraRXBuffer, 0, RXBuffSize); // Clear saraRXBuffer + + int backlogLen = strlen(saraResponseBacklog); // Check how many bytes are in the backlog + + // Does the backlog contain any data? If it does, copy it into saraRXBuffer and then clear the backlog + if (backlogLen > 0) { //The backlog also logs reads from other tasks like transmitting. - if (_printDebug == true) _debugPort->println("Backlog found!"); - memcpy(saraRXBuffer+avail, saraResponseBacklog, backlogLen); - avail+=backlogLen; - memset(saraResponseBacklog, 0, RXBuffSize); - } + if (_printDebug == true) + _debugPort->println(F("bufferedPoll: backlog found!")); + memcpy(saraRXBuffer + avail, saraResponseBacklog, backlogLen); + avail += backlogLen; + memset(saraResponseBacklog, 0, RXBuffSize); // Clear the backlog making sure it is NULL-terminated + } - if (hwAvailable() > 0 || backlogLen > 0) // If either new data is available, or backlog had data. + if ((hwAvailable() > 0) || (backlogLen > 0)) // If either new data is available, or backlog had data. { - while (micros() - timeIn < rxWindowUS && avail < RXBuffSize) + // Wait for up to rxWindowUS for new serial data to arrive. + while (((micros() - timeIn) < rxWindowUS) && (avail < RXBuffSize)) { - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL { - c = readChar(); - saraRXBuffer[avail++] = c; - timeIn = micros(); + c = readChar(); + saraRXBuffer[avail++] = c; + timeIn = micros(); } - } - event = strtok(saraRXBuffer, "\r\n"); - while (event != NULL) + } + + // saraRXBuffer now contains the backlog (if any) and the new serial data (if any) + + event = strtok(saraRXBuffer, "\r\n"); // Look for an 'event' (saraRXBuffer contains something ending in \r\n) + + while (event != NULL) // Keep going until all events have been processed { - if (_printDebug == true) _debugPort->print("Event:"); - if (_printDebug == true) _debugPort->print(event); - handled = processReadEvent(event); - backlogLen = strlen(saraResponseBacklog); - if (backlogLen > 0 && (avail+backlogLen) < RXBuffSize) + if (_printDebug == true) + _debugPort->print(F("bufferedPoll: event: ")); + if (_printDebug == true) + _debugPort->println(event); + + //Process the event + bool latestHandled = processURCEvent((const char *)event); + if (latestHandled) + handled = true; // handled will be true if latestHandled has ever been true + + backlogLen = strlen(saraResponseBacklog); // Has any new data been added to the backlog? + if ((backlogLen > 0) && ((avail + backlogLen) < RXBuffSize)) { - if (_printDebug == true) _debugPort->println("Backlog added!"); - memcpy(saraRXBuffer+avail, saraResponseBacklog, backlogLen); - avail+=backlogLen; - memset(saraResponseBacklog, 0, RXBuffSize);//Clear out backlog buffer. - } - event = strtok(NULL, "\r\n"); - if (_printDebug == true) _debugPort->println("!");//Just to denote end of processing event. + if (_printDebug == true) + _debugPort->println(F("bufferedPoll: new backlog added!")); + memcpy(saraRXBuffer + avail, saraResponseBacklog, backlogLen); + avail += backlogLen; + memset(saraResponseBacklog, 0, RXBuffSize); //Clear out backlog buffer. Again. + } + + //Walk through any remaining events + event = strtok(NULL, "\r\n"); + if (_printDebug == true) + _debugPort->println(F("bufferedPoll: end of event")); //Just to denote end of processing event. } } - free(event); + + free(event); return handled; } -bool SARA_R5::processReadEvent(char* event) -{ - { - int socket, length; - int ret = sscanf(event, "+UUSORD: %d,%d", &socket, &length); - if (ret == 2) - { - if (_printDebug == true) _debugPort->println("PARSED SOCKET READ"); - parseSocketReadIndication(socket, length); - return true; - } - } - { - int socket, length; - int ret = sscanf(event, "+UUSORF: %d,%d", &socket, &length); - if (ret == 2) +bool SARA_R5::processURCEvent(const char *event) +{ + { + int socket, length; + int ret = sscanf(event, "+UUSORD: %d,%d", &socket, &length); + if (ret == 2) { - if (_printDebug == true) _debugPort->println("PARSED UDP READ"); - parseSocketReadIndicationUDP(socket, length); - return true; - } - } - { - int socket, listenSocket; - unsigned int port, listenPort; - IPAddress remoteIP, localIP; - int remoteIPstore[4], localIPstore[4]; - int ret = sscanf(event, - "+UUSOLI: %d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", - &socket, - &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], - &port, &listenSocket, - &localIPstore[0], &localIPstore[1], &localIPstore[2], &localIPstore[3], - &listenPort); - for (int i = 0; i <= 3; i++) + if (_printDebug == true) + _debugPort->println(F("processReadEvent: read socket data")); + parseSocketReadIndication(socket, length); + return true; + } + } + { + int socket, length; + int ret = sscanf(event, "+UUSORF: %d,%d", &socket, &length); + if (ret == 2) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: UDP receive")); + parseSocketReadIndicationUDP(socket, length); + return true; + } + } + { + int socket = 0; + int listenSocket = 0; + unsigned int port = 0; + unsigned int listenPort = 0; + IPAddress remoteIP = {0,0,0,0}; + IPAddress localIP = {0,0,0,0}; + int remoteIPstore[4] = {0,0,0,0}; + int localIPstore[4] = {0,0,0,0}; + + int ret = sscanf(event, + "+UUSOLI: %d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", + &socket, + &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], + &port, &listenSocket, + &localIPstore[0], &localIPstore[1], &localIPstore[2], &localIPstore[3], + &listenPort); + for (int i = 0; i <= 3; i++) + { + remoteIP[i] = (uint8_t)remoteIPstore[i]; + localIP[i] = (uint8_t)localIPstore[i]; + } + if (ret > 4) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: socket listen")); + parseSocketListenIndication(listenSocket, localIP, listenPort, socket, remoteIP, port); + return true; + } + } + { + int socket; + int ret = sscanf(event, "+UUSOCL: %d", &socket); + if (ret == 1) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: socket close")); + if ((socket >= 0) && (socket <= 6)) + { + if (_socketCloseCallback != NULL) { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - localIP[i] = (uint8_t)localIPstore[i]; + _socketCloseCallback(socket); } - if (ret > 4) - { - if (_printDebug == true) _debugPort->println("PARSED SOCKET LISTEN"); - parseSocketListenIndication(localIP, remoteIP); - return true; - } - } - { - int socket; - int ret = sscanf(event, "+UUSOCL: %d", &socket); - if (ret == 1) - { - if (_printDebug == true) _debugPort->println("PARSED SOCKET CLOSE"); - if ((socket >= 0) && (socket <= 6)) - { - if (_socketCloseCallback != NULL) - { - _socketCloseCallback(socket); - } - } - return true; - } - } - return false; -} - -bool SARA_R5::poll(void) -{ - int avail = 0; - char c = 0; - bool handled = false; + } + return true; + } + } + { + ClockData clck; + PositionData gps; + SpeedData spd; + unsigned long uncertainty; + int scanNum; + int latH, lonH, alt; + unsigned int speedU, cogU; + char latL[10], lonL[10]; + int dateStore[5]; + + // Maybe we should also scan for +UUGIND and extract the activated gnss system? + + // This assumes the ULOC response type is "0" or "1" - as selected by gpsRequest detailed + scanNum = sscanf(event, + "+UULOC: %d/%d/%d,%d:%d:%d.%d,%d.%[^,],%d.%[^,],%d,%lu,%u,%u,%*s", + &dateStore[0], &dateStore[1], &clck.date.year, + &dateStore[2], &dateStore[3], &dateStore[4], &clck.time.ms, + &latH, latL, &lonH, lonL, &alt, &uncertainty, + &speedU, &cogU); + clck.date.day = dateStore[0]; + clck.date.month = dateStore[1]; + clck.time.hour = dateStore[2]; + clck.time.minute = dateStore[3]; + clck.time.second = dateStore[4]; + + if (scanNum >= 13) + { + // Found a Location string! + if (_printDebug == true) + { + _debugPort->println(F("processReadEvent: location")); + } - memset(saraRXBuffer, 0, RXBuffSize); + if (latH >= 0) + gps.lat = (float)latH + ((float)atol(latL) / pow(10, strlen(latL))); + else + gps.lat = (float)latH - ((float)atol(latL) / pow(10, strlen(latL))); + if (lonH >= 0) + gps.lon = (float)lonH + ((float)atol(lonL) / pow(10, strlen(lonL))); + else + gps.lon = (float)lonH - ((float)atol(lonL) / pow(10, strlen(lonL))); + gps.alt = (float)alt; + if (scanNum >= 15) // If detailed response, get speed data + { + spd.speed = (float)speedU; + spd.cog = (float)cogU; + } - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL - { - while (c != '\n') - { - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL - { - c = readChar(); - saraRXBuffer[avail++] = c; - } - } - { - int socket, length; - if (sscanf(saraRXBuffer, "+UUSORD: %d,%d", &socket, &length) == 2) - { - parseSocketReadIndication(socket, length); - handled = true; - } - } - { - int socket, listenSocket; - unsigned int port, listenPort; - IPAddress remoteIP, localIP; - - int remoteIPstore[4], localIPstore[4]; - int ret = sscanf(saraRXBuffer, - "+UUSOLI: %d,\"%d.%d.%d.%d\",%u,%d,\"%d.%d.%d.%d\",%u", - &socket, - &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], - &port, &listenSocket, - &localIPstore[0], &localIPstore[1], &localIPstore[2], &localIPstore[3], - &listenPort); - for (int i = 0; i <= 3; i++) - { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - localIP[i] = (uint8_t)localIPstore[i]; - } - if (ret > 4) - { - parseSocketListenIndication(localIP, remoteIP); - handled = true; - } - } - { - int socket; + // if (_printDebug == true) + // { + // _debugPort->print(F("processReadEvent: location: lat: ")); + // _debugPort->print(gps.lat, 7); + // _debugPort->print(F(" lon: ")); + // _debugPort->print(gps.lon, 7); + // _debugPort->print(F(" alt: ")); + // _debugPort->print(gps.alt, 2); + // _debugPort->print(F(" speed: ")); + // _debugPort->print(spd.speed, 2); + // _debugPort->print(F(" cog: ")); + // _debugPort->println(spd.cog, 2); + // } + + if (_gpsRequestCallback != NULL) + { + _gpsRequestCallback(clck, gps, spd, uncertainty); + } - if (sscanf(saraRXBuffer, - "+UUSOCL: %d", &socket) == 1) - { - if ((socket >= 0) && (socket <= 6)) - { - if (_socketCloseCallback != NULL) - { - _socketCloseCallback(socket); - } - } - handled = true; - } - } - { - ClockData clck; - PositionData gps; - SpeedData spd; - unsigned long uncertainty; - int scanNum; - int latH, lonH, alt; - unsigned int speedU, cogU; - char latL[10], lonL[10]; - - // Maybe we should also scan for +UUGIND and extract the activated gnss system? - - if (strstr(saraRXBuffer, "+UULOC")) - { - // Found a Location string! - if (_printDebug == true) - { - _debugPort->print("poll +UULOC: saraRXBuffer: "); - _debugPort->println(saraRXBuffer); - } + return true; + } + } + { + SARA_R5_sim_states_t state; + int scanNum; + int stateStore; - // This assumes the ULOC response type is "0" or "1" - as selected by gpsRequest detailed - int dateStore[5]; - scanNum = sscanf(saraRXBuffer, - "+UULOC: %d/%d/%d,%d:%d:%d.%d,%d.%[^,],%d.%[^,],%d,%lu,%u,%u,%*s", - &dateStore[0], &dateStore[1], &clck.date.year, - &dateStore[2], &dateStore[3], &dateStore[4], &clck.time.ms, - &latH, latL, &lonH, lonL, &alt, &uncertainty, - &speedU, &cogU); - clck.date.day = dateStore[0]; - clck.date.month = dateStore[1]; - clck.time.hour = dateStore[2]; - clck.time.minute = dateStore[3]; - clck.time.second = dateStore[4]; - if (scanNum < 13) - return false; // Break out if we didn't find enough - - if (latH >= 0) - gps.lat = (float)latH + ((float)atol(latL) / pow(10, strlen(latL))); - else - gps.lat = (float)latH - ((float)atol(latL) / pow(10, strlen(latL))); - if (lonH >= 0) - gps.lon = (float)lonH + ((float)atol(lonL) / pow(10, strlen(lonL))); - else - gps.lon = (float)lonH - ((float)atol(lonL) / pow(10, strlen(lonL))); - gps.alt = (float)alt; - if (scanNum >= 15) // If detailed response, get speed data - { - spd.speed = (float)speedU; - spd.cog = (float)cogU; - } + scanNum = sscanf(event, "+UUSIMSTAT:%d", &stateStore); - if (_printDebug == true) - { - _debugPort->print("poll +UULOC: lat: "); - _debugPort->print(gps.lat, 7); - _debugPort->print(" lon: "); - _debugPort->print(gps.lon, 7); - _debugPort->print(" alt: "); - _debugPort->print(gps.alt, 2); - _debugPort->print(" speed: "); - _debugPort->print(spd.speed, 2); - _debugPort->print(" cog: "); - _debugPort->println(spd.cog, 2); - } + if (scanNum == 1) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: SIM status")); - if (_gpsRequestCallback != NULL) - { - _gpsRequestCallback(clck, gps, spd, uncertainty); - } + state = (SARA_R5_sim_states_t)stateStore; - handled = true; - } - } - { - SARA_R5_sim_states_t state; - int scanNum; + if (_simStateReportCallback != NULL) + { + _simStateReportCallback(state); + } - if (strstr(saraRXBuffer, "+UUSIMSTAT")) - { - int stateStore; - scanNum = sscanf(saraRXBuffer, "+UUSIMSTAT:%d", &stateStore); - state = (SARA_R5_sim_states_t)stateStore; - if (scanNum < 1) - return false; // Break out if we didn't find enough + return true; + } + } + { + int result; + IPAddress remoteIP = {0, 0, 0, 0}; + int scanNum; + int remoteIPstore[4]; - if (_simStateReportCallback != NULL) - { - _simStateReportCallback(state); - } + scanNum = sscanf(event, "+UUPSDA: %d,\"%d.%d.%d.%d\"", + &result, &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3]); - handled = true; - } - } - { - int result; - IPAddress remoteIP = {0,0,0,0}; - int scanNum; + if (scanNum == 5) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: packet switched data action")); - if (strstr(saraRXBuffer, "+UUPSDA")) - { - int remoteIPstore[4]; - scanNum = sscanf(saraRXBuffer, "+UUPSDA: %d,\"%d.%d.%d.%d\"", - &result, &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3]); - for (int i = 0; i <= 3; i++) - { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - } - if (scanNum < 1) - return false; // Break out if we didn't find enough + for (int i = 0; i <= 3; i++) + { + remoteIP[i] = (uint8_t)remoteIPstore[i]; + } - if (_psdActionRequestCallback != NULL) - { - _psdActionRequestCallback(result, remoteIP); - } + if (_psdActionRequestCallback != NULL) + { + _psdActionRequestCallback(result, remoteIP); + } - handled = true; - } - } - { - int retry = 0; - int p_size = 0; - int ttl = 0; - String remote_host = ""; - IPAddress remoteIP = {0,0,0,0}; - long rtt = 0; - int scanNum; - char *searchPtr = saraRXBuffer; - - // Find the first/next occurrence of +UUPING: - searchPtr = strstr(searchPtr, "+UUPING: "); - if (searchPtr != NULL) - { - //if (_printDebug == true) - //{ - // _debugPort->print("poll +UUPING: saraRXBuffer: "); - // _debugPort->println(saraRXBuffer); - //} + return true; + } + } + { + int profile, command, result; + int scanNum; - // Extract the retries and payload size - scanNum = sscanf(searchPtr, "+UUPING: %d,%d,", &retry, &p_size); + scanNum = sscanf(event, "+UUHTTPCR: %d,%d,%d", &profile, &command, &result); - if (scanNum < 2) - return false; // Break out if we didn't find enough + if (scanNum == 3) + { + if (_printDebug == true) + _debugPort->println(F("processReadEvent: HTTP command result")); - searchPtr = strchr(++searchPtr, '\"'); // Search to the first quote + if ((profile >= 0) && (profile < SARA_R5_NUM_HTTP_PROFILES)) + { + if (_httpCommandRequestCallback != NULL) + { + _httpCommandRequestCallback(profile, command, result); + } + } - // Extract the remote host name, stop at the next quote - while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) - { - remote_host.concat(*(searchPtr)); - } + return true; + } + } + // Save UUPING until last as it probably has the most chance of going wrong? + { + int retry = 0; + int p_size = 0; + int ttl = 0; + String remote_host = ""; + IPAddress remoteIP = {0, 0, 0, 0}; + long rtt = 0; + int scanNum; + const char *searchPtr = event; - if (*searchPtr == '\0') - return false; // Break out if we didn't find enough + // Try to extract the UUPING retries and payload size + scanNum = sscanf(searchPtr, "+UUPING: %d,%d,", &retry, &p_size); - int remoteIPstore[4]; - scanNum = sscanf(searchPtr, "\",\"%d.%d.%d.%d\",%d,%ld", - &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], &ttl, &rtt); - for (int i = 0; i <= 3; i++) - { - remoteIP[i] = (uint8_t)remoteIPstore[i]; - } + if (scanNum == 2) + { + if (_printDebug == true) + { + _debugPort->println(F("processReadEvent: ping")); + } - if (scanNum < 6) - return false; // Break out if we didn't find enough + searchPtr = strchr(++searchPtr, '\"'); // Search to the first quote - if (_pingRequestCallback != NULL) - { - _pingRequestCallback(retry, p_size, remote_host, remoteIP, ttl, rtt); - } + // Extract the remote host name, stop at the next quote + while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) + { + remote_host.concat(*(searchPtr)); + } - handled = true; - } + if (*searchPtr != '\0') // Make sure we found a quote + { + int remoteIPstore[4]; + scanNum = sscanf(searchPtr, "\",\"%d.%d.%d.%d\",%d,%ld", + &remoteIPstore[0], &remoteIPstore[1], &remoteIPstore[2], &remoteIPstore[3], &ttl, &rtt); + for (int i = 0; i <= 3; i++) + { + remoteIP[i] = (uint8_t)remoteIPstore[i]; } + + if (scanNum == 6) // Make sure we extracted enough data { - int profile, command, result; - int scanNum; + if (_pingRequestCallback != NULL) + { + _pingRequestCallback(retry, p_size, remote_host, remoteIP, ttl, rtt); + } + } + } + return true; + } + } + return false; +} - if (strstr(saraRXBuffer, "+UUHTTPCR")) - { - scanNum = sscanf(saraRXBuffer, "+UUHTTPCR: %d,%d,%d", &profile, &command, &result); - if (scanNum < 3) - return false; // Break out if we didn't find enough +// This is the original poll function. +// It is 'blocking' - it does not return when serial data is available until it receives a `\n`. +// ::bufferedPoll is the new improved version. It processes any data in the backlog and includes a timeout. +bool SARA_R5::poll(void) +{ + int avail = 0; + char c = 0; + bool handled = false; - if ((profile >= 0) && (profile < SARA_R5_NUM_HTTP_PROFILES)) - { - if (_httpCommandRequestCallback != NULL) - { - _httpCommandRequestCallback(profile, command, result); - } - } + memset(saraRXBuffer, 0, RXBuffSize); // Clear saraRXBuffer - handled = true; - } - } + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + { + while (c != '\n') // Copy characters into saraRXBuffer. Stop at the first new line + { + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + { + c = readChar(); + saraRXBuffer[avail++] = c; + } + } - if ((handled == false) && (strlen(saraRXBuffer) > 2)) - { - if (_printDebug == true) _debugPort->println("Poll: " + String(saraRXBuffer)); - } - else - { - } + // Now search for all supported URC's + handled = processURCEvent(saraRXBuffer); + + if ((handled == false) && (strlen(saraRXBuffer) > 2)) + { + if (_printDebug == true) + { + _debugPort->print(F("poll: ")); + _debugPort->println(saraRXBuffer); + } + } + else + { } - return handled; + } + return handled; +} + +void SARA_R5::setSocketListenCallback(void (*socketListenCallback)(int, IPAddress, unsigned int, int, IPAddress, unsigned int)) +{ + _socketListenCallback = socketListenCallback; } void SARA_R5::setSocketReadCallback(void (*socketReadCallback)(int, String)) { - _socketReadCallback = socketReadCallback; + _socketReadCallback = socketReadCallback; } void SARA_R5::setSocketCloseCallback(void (*socketCloseCallback)(int)) { - _socketCloseCallback = socketCloseCallback; + _socketCloseCallback = socketCloseCallback; } void SARA_R5::setGpsReadCallback(void (*gpsRequestCallback)(ClockData time, - PositionData gps, SpeedData spd, unsigned long uncertainty)) + PositionData gps, SpeedData spd, unsigned long uncertainty)) { - _gpsRequestCallback = gpsRequestCallback; + _gpsRequestCallback = gpsRequestCallback; } -void SARA_R5::setSIMstateReportCallback(void (*simStateReportCallback) - (SARA_R5_sim_states_t state)) +void SARA_R5::setSIMstateReportCallback(void (*simStateReportCallback)(SARA_R5_sim_states_t state)) { - _simStateReportCallback = simStateReportCallback; + _simStateReportCallback = simStateReportCallback; } -void SARA_R5::setPSDActionCallback(void (*psdActionRequestCallback) - (int result, IPAddress ip)) +void SARA_R5::setPSDActionCallback(void (*psdActionRequestCallback)(int result, IPAddress ip)) { - _psdActionRequestCallback = psdActionRequestCallback; + _psdActionRequestCallback = psdActionRequestCallback; } -void SARA_R5::setPingCallback(void (*pingRequestCallback) - (int retry, int p_size, String remote_hostname, IPAddress ip, int ttl, long rtt)) +void SARA_R5::setPingCallback(void (*pingRequestCallback)(int retry, int p_size, String remote_hostname, IPAddress ip, int ttl, long rtt)) { - _pingRequestCallback = pingRequestCallback; + _pingRequestCallback = pingRequestCallback; } -void SARA_R5::setHTTPCommandCallback(void (*httpCommandRequestCallback) - (int profile, int command, int result)) +void SARA_R5::setHTTPCommandCallback(void (*httpCommandRequestCallback)(int profile, int command, int result)) { - _httpCommandRequestCallback = httpCommandRequestCallback; + _httpCommandRequestCallback = httpCommandRequestCallback; } size_t SARA_R5::write(uint8_t c) { - if (_hardSerial != NULL) - { - return _hardSerial->write(c); - } + if (_hardSerial != NULL) + { + return _hardSerial->write(c); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->write(c); - } + else if (_softSerial != NULL) + { + return _softSerial->write(c); + } #endif - return (size_t)0; + return (size_t)0; } size_t SARA_R5::write(const char *str) { - if (_hardSerial != NULL) - { - return _hardSerial->print(str); - } + if (_hardSerial != NULL) + { + return _hardSerial->print(str); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->print(str); - } + else if (_softSerial != NULL) + { + return _softSerial->print(str); + } #endif - return (size_t)0; + return (size_t)0; } size_t SARA_R5::write(const char *buffer, size_t size) { - //size is unused at the moment but could be used if this function is ever updated to use write instead of print. - size_t ignoreMe = size; ignoreMe -= 0; // Avoid the pesky compiler warning. + //size is unused at the moment but could be used if this function is ever updated to use write instead of print. + size_t ignoreMe = size; + ignoreMe -= 0; // Avoid the pesky compiler warning. - if (_hardSerial != NULL) - { - return _hardSerial->print(buffer); - } + if (_hardSerial != NULL) + { + return _hardSerial->print(buffer); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->print(buffer); - } + else if (_softSerial != NULL) + { + return _softSerial->print(buffer); + } #endif - return (size_t)0; + return (size_t)0; } SARA_R5_error_t SARA_R5::at(void) { - SARA_R5_error_t err; + SARA_R5_error_t err; - err = sendCommandWithResponse(NULL, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(NULL, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - return err; + return err; } SARA_R5_error_t SARA_R5::enableEcho(bool enable) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_ECHO) + 2); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (enable) - { - sprintf(command, "%s1", SARA_R5_COMMAND_ECHO); - } - else - { - sprintf(command, "%s0", SARA_R5_COMMAND_ECHO); - } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_ECHO) + 2); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (enable) + { + sprintf(command, "%s1", SARA_R5_COMMAND_ECHO); + } + else + { + sprintf(command, "%s0", SARA_R5_COMMAND_ECHO); + } + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); + free(command); - return err; + return err; } String SARA_R5::getManufacturerID(void) { - char *response; - char idResponse[16] = { 0x00 }; // E.g. u-blox - SARA_R5_error_t err; + char *response; + char idResponse[16] = {0x00}; // E.g. u-blox + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_MANU_ID, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_MANU_ID, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) - { - memset(idResponse, 0, 16); - } + memset(idResponse, 0, 16); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } String SARA_R5::getModelID(void) { - char *response; - char idResponse[16] = { 0x00 }; // E.g. SARA-R510M8Q - SARA_R5_error_t err; + char *response; + char idResponse[16] = {0x00}; // E.g. SARA-R510M8Q + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_MODEL_ID, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_MODEL_ID, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) - { - memset(idResponse, 0, 16); - } + memset(idResponse, 0, 16); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } String SARA_R5::getFirmwareVersion(void) { - char *response; - char idResponse[16] = { 0x00 }; // E.g. 11.40 - SARA_R5_error_t err; + char *response; + char idResponse[16] = {0x00}; // E.g. 11.40 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_FW_VER_ID, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_FW_VER_ID, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) - { - memset(idResponse, 0, 16); - } + memset(idResponse, 0, 16); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } String SARA_R5::getSerialNo(void) { - char *response; - char idResponse[16] = { 0x00 }; // E.g. 357520070120767 - SARA_R5_error_t err; + char *response; + char idResponse[16] = {0x00}; // E.g. 357520070120767 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_SERIAL_NO, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_SERIAL_NO, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", idResponse) != 1) - { - memset(idResponse, 0, 16); - } + memset(idResponse, 0, 16); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } String SARA_R5::getIMEI(void) { - char *response; - char imeiResponse[16] = { 0x00 }; // E.g. 004999010640000 - SARA_R5_error_t err; + char *response; + char imeiResponse[16] = {0x00}; // E.g. 004999010640000 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(imeiResponse) + 16); + response = sara_r5_calloc_char(sizeof(imeiResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_IMEI, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_IMEI, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", imeiResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", imeiResponse) != 1) - { - memset(imeiResponse, 0, 16); - } + memset(imeiResponse, 0, 16); } - free(response); - return String(imeiResponse); + } + free(response); + return String(imeiResponse); } String SARA_R5::getIMSI(void) { - char *response; - char imsiResponse[16] = { 0x00 }; // E.g. 222107701772423 - SARA_R5_error_t err; + char *response; + char imsiResponse[16] = {0x00}; // E.g. 222107701772423 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(imsiResponse) + 16); + response = sara_r5_calloc_char(sizeof(imsiResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_IMSI, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_IMSI, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n%s\r\n", imsiResponse) != 1) { - if (sscanf(response, "\r\n%s\r\n", imsiResponse) != 1) - { - memset(imsiResponse, 0, 16); - } + memset(imsiResponse, 0, 16); } - free(response); - return String(imsiResponse); + } + free(response); + return String(imsiResponse); } String SARA_R5::getCCID(void) { - char *response; - char ccidResponse[21] = { 0x00 }; // E.g. +CCID: 8939107900010087330 - SARA_R5_error_t err; + char *response; + char ccidResponse[21] = {0x00}; // E.g. +CCID: 8939107900010087330 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(ccidResponse) + 16); + response = sara_r5_calloc_char(sizeof(ccidResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_CCID, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_CCID, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n+CCID: %s", ccidResponse) != 1) { - if (sscanf(response, "\r\n+CCID: %s", ccidResponse) != 1) - { - memset(ccidResponse, 0, 21); - } + memset(ccidResponse, 0, 21); } - free(response); - return String(ccidResponse); + } + free(response); + return String(ccidResponse); } String SARA_R5::getSubscriberNo(void) { - char *response; - char idResponse[128] = { 0x00 }; // E.g. +CNUM: "ABCD . AAA","123456789012",129 - SARA_R5_error_t err; + char *response; + char idResponse[128] = {0x00}; // E.g. +CNUM: "ABCD . AAA","123456789012",129 + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_CNUM, - SARA_R5_RESPONSE_OK, response, SARA_R5_10_SEC_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_CNUM, + SARA_R5_RESPONSE_OK, response, SARA_R5_10_SEC_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n+CNUM: %s", idResponse) != 1) { - if (sscanf(response, "\r\n+CNUM: %s", idResponse) != 1) - { - memset(idResponse, 0, 128); - } + memset(idResponse, 0, 128); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } String SARA_R5::getCapabilities(void) { - char *response; - char idResponse[128] = { 0x00 }; // E.g. +GCAP: +FCLASS, +CGSM - SARA_R5_error_t err; + char *response; + char idResponse[128] = {0x00}; // E.g. +GCAP: +FCLASS, +CGSM + SARA_R5_error_t err; - response = sara_r5_calloc_char(sizeof(idResponse) + 16); + response = sara_r5_calloc_char(sizeof(idResponse) + 16); - err = sendCommandWithResponse(SARA_R5_COMMAND_REQ_CAP, - SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + err = sendCommandWithResponse(SARA_R5_COMMAND_REQ_CAP, + SARA_R5_RESPONSE_OK, response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n+GCAP: %s", idResponse) != 1) { - if (sscanf(response, "\r\n+GCAP: %s", idResponse) != 1) - { - memset(idResponse, 0, 128); - } + memset(idResponse, 0, 128); } - free(response); - return String(idResponse); + } + free(response); + return String(idResponse); } SARA_R5_error_t SARA_R5::reset(void) { - SARA_R5_error_t err; + SARA_R5_error_t err; - err = functionality(SILENT_RESET_WITH_SIM); - if (err == SARA_R5_ERROR_SUCCESS) - { - // Reset will set the baud rate back to 115200 - //beginSerial(9600); - err = SARA_R5_ERROR_INVALID; - while (err != SARA_R5_ERROR_SUCCESS) - { - beginSerial(SARA_R5_DEFAULT_BAUD_RATE); - setBaud(_baud); - delay(200); - beginSerial(_baud); - err = at(); - delay(500); - } - return init(_baud); - } - return err; + err = functionality(SILENT_RESET_WITH_SIM); + if (err == SARA_R5_ERROR_SUCCESS) + { + // Reset will set the baud rate back to 115200 + //beginSerial(9600); + err = SARA_R5_ERROR_INVALID; + while (err != SARA_R5_ERROR_SUCCESS) + { + beginSerial(SARA_R5_DEFAULT_BAUD_RATE); + setBaud(_baud); + delay(200); + beginSerial(_baud); + err = at(); + delay(500); + } + return init(_baud); + } + return err; } String SARA_R5::clock(void) { - SARA_R5_error_t err; - char *command; - char *response; - char *clockBegin; - char *clockEnd; - - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_CLOCK) + 2); - if (command == NULL) - return ""; - sprintf(command, "%s?", SARA_R5_COMMAND_CLOCK); + SARA_R5_error_t err; + char *command; + char *response; + char *clockBegin; + char *clockEnd; - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return ""; - } + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_CLOCK) + 2); + if (command == NULL) + return ""; + sprintf(command, "%s?", SARA_R5_COMMAND_CLOCK); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return ""; - } + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return ""; + } - // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n - clockBegin = strchr(response, '\"'); // Find first quote - if (clockBegin == NULL) - { - free(command); - free(response); - return ""; - } - clockBegin += 1; // Increment pointer to begin at first number - clockEnd = strchr(clockBegin, '\"'); // Find last quote - if (clockEnd == NULL) - { - free(command); - free(response); - return ""; - } - *(clockEnd) = '\0'; // Set last quote to null char -- end string + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err != SARA_R5_ERROR_SUCCESS) + { + free(command); + free(response); + return ""; + } + // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n + clockBegin = strchr(response, '\"'); // Find first quote + if (clockBegin == NULL) + { + free(command); + free(response); + return ""; + } + clockBegin += 1; // Increment pointer to begin at first number + clockEnd = strchr(clockBegin, '\"'); // Find last quote + if (clockEnd == NULL) + { free(command); free(response); + return ""; + } + *(clockEnd) = '\0'; // Set last quote to null char -- end string - return String(clockBegin); + free(command); + free(response); + + return String(clockBegin); } SARA_R5_error_t SARA_R5::clock(uint8_t *y, uint8_t *mo, uint8_t *d, - uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz) + uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz) { - SARA_R5_error_t err; - char *command; - char *response; + SARA_R5_error_t err; + char *command; + char *response; - int iy, imo, id, ih, imin, is, itz; + int iy, imo, id, ih, imin, is, itz; - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_CLOCK) + 2); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_COMMAND_CLOCK); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_CLOCK) + 2); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_COMMAND_CLOCK); - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n - if (err == SARA_R5_ERROR_SUCCESS) + // Response format: \r\n+CCLK: "YY/MM/DD,HH:MM:SS-TZ"\r\n\r\nOK\r\n + if (err == SARA_R5_ERROR_SUCCESS) + { + if (sscanf(response, "\r\n+CCLK: \"%d/%d/%d,%d:%d:%d-%d\"\r\n", + &iy, &imo, &id, &ih, &imin, &is, &itz) == 7) { - if (sscanf(response, "\r\n+CCLK: \"%d/%d/%d,%d:%d:%d-%d\"\r\n", - &iy, &imo, &id, &ih, &imin, &is, &itz) == 7) - { - *y = iy; - *mo = imo; - *d = id; - *h = ih; - *min = imin; - *s = is; - *tz = itz; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + *y = iy; + *mo = imo; + *d = id; + *h = ih; + *min = imin; + *s = is; + *tz = itz; } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - free(command); - free(response); - return err; + free(command); + free(response); + return err; } SARA_R5_error_t SARA_R5::setUtimeMode(SARA_R5_utime_mode_t mode, SARA_R5_utime_sensor_t sensor) @@ -911,7 +907,7 @@ SARA_R5_error_t SARA_R5::setUtimeMode(SARA_R5_utime_mode_t mode, SARA_R5_utime_s command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_REQUEST_TIME) + 16); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; if (mode == SARA_R5_UTIME_MODE_STOP) // stop UTIME does not require a sensor sprintf(command, "%s=%d", SARA_R5_GNSS_REQUEST_TIME, mode); else @@ -934,14 +930,14 @@ SARA_R5_error_t SARA_R5::getUtimeMode(SARA_R5_utime_mode_t *mode, SARA_R5_utime_ command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_REQUEST_TIME) + 2); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s?", SARA_R5_GNSS_REQUEST_TIME); response = sara_r5_calloc_char(48); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -950,21 +946,22 @@ SARA_R5_error_t SARA_R5::getUtimeMode(SARA_R5_utime_mode_t *mode, SARA_R5_utime_ // Response format: \r\n+UTIME: [,]\r\n\r\nOK\r\n if (err == SARA_R5_ERROR_SUCCESS) { - int mStore, sStore; - int scanned = sscanf(response, "\r\n+UTIME: %d,%d\r\n", &mStore, &sStore); - m = (SARA_R5_utime_mode_t)mStore; - s = (SARA_R5_utime_sensor_t)sStore; - if (scanned == 2) - { - *mode = m; - *sensor = s; - } - else if (scanned == 1) - { - *mode = m; - *sensor = SARA_R5_UTIME_SENSOR_NONE; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + int mStore, sStore; + int scanned = sscanf(response, "\r\n+UTIME: %d,%d\r\n", &mStore, &sStore); + m = (SARA_R5_utime_mode_t)mStore; + s = (SARA_R5_utime_sensor_t)sStore; + if (scanned == 2) + { + *mode = m; + *sensor = s; + } + else if (scanned == 1) + { + *mode = m; + *sensor = SARA_R5_UTIME_SENSOR_NONE; + } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -979,7 +976,7 @@ SARA_R5_error_t SARA_R5::setUtimeIndication(SARA_R5_utime_urc_configuration_t co command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_TIME_INDICATION) + 16); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s=%d", SARA_R5_GNSS_TIME_INDICATION, config); err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -998,14 +995,14 @@ SARA_R5_error_t SARA_R5::getUtimeIndication(SARA_R5_utime_urc_configuration_t *c command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_TIME_INDICATION) + 2); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s?", SARA_R5_GNSS_TIME_INDICATION); response = sara_r5_calloc_char(48); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -1014,14 +1011,15 @@ SARA_R5_error_t SARA_R5::getUtimeIndication(SARA_R5_utime_urc_configuration_t *c // Response format: \r\n+UTIMEIND: \r\n\r\nOK\r\n if (err == SARA_R5_ERROR_SUCCESS) { - int cStore; - int scanned = sscanf(response, "\r\n+UTIMEIND: %d\r\n", &cStore); - c = (SARA_R5_utime_urc_configuration_t)cStore; - if (scanned == 1) - { - *config = c; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + int cStore; + int scanned = sscanf(response, "\r\n+UTIMEIND: %d\r\n", &cStore); + c = (SARA_R5_utime_urc_configuration_t)cStore; + if (scanned == 1) + { + *config = c; + } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -1036,7 +1034,7 @@ SARA_R5_error_t SARA_R5::setUtimeConfiguration(int32_t offsetNanoseconds, int32_ command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_TIME_CONFIGURATION) + 48); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) sprintf(command, "%s=%d,%d", SARA_R5_GNSS_TIME_CONFIGURATION, offsetNanoseconds, offsetSeconds); #else @@ -1060,14 +1058,14 @@ SARA_R5_error_t SARA_R5::getUtimeConfiguration(int32_t *offsetNanoseconds, int32 command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_TIME_CONFIGURATION) + 2); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s?", SARA_R5_GNSS_TIME_CONFIGURATION); response = sara_r5_calloc_char(48); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -1077,16 +1075,17 @@ SARA_R5_error_t SARA_R5::getUtimeConfiguration(int32_t *offsetNanoseconds, int32 if (err == SARA_R5_ERROR_SUCCESS) { #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) - int scanned = sscanf(response, "\r\n+UTIMECFG: %d,%d\r\n", &ons, &os); + int scanned = sscanf(response, "\r\n+UTIMECFG: %d,%d\r\n", &ons, &os); #else - int scanned = sscanf(response, "\r\n+UTIMECFG: %ld,%ld\r\n", &ons, &os); + int scanned = sscanf(response, "\r\n+UTIMECFG: %ld,%ld\r\n", &ons, &os); #endif - if (scanned == 2) - { - *offsetNanoseconds = ons; - *offsetSeconds = os; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + if (scanned == 2) + { + *offsetNanoseconds = ons; + *offsetSeconds = os; + } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -1096,305 +1095,314 @@ SARA_R5_error_t SARA_R5::getUtimeConfiguration(int32_t *offsetNanoseconds, int32 SARA_R5_error_t SARA_R5::autoTimeZone(bool enable) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_AUTO_TZ) + 3); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_COMMAND_AUTO_TZ, enable ? 1 : 0); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_AUTO_TZ) + 3); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_COMMAND_AUTO_TZ, enable ? 1 : 0); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + free(command); + return err; } int8_t SARA_R5::rssi(void) { - char *command; - char *response; - SARA_R5_error_t err; - int rssi; - - command = sara_r5_calloc_char(strlen(SARA_R5_SIGNAL_QUALITY) + 1); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s", SARA_R5_SIGNAL_QUALITY); - - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + char *command; + char *response; + SARA_R5_error_t err; + int rssi; - err = sendCommandWithResponse(command, - SARA_R5_RESPONSE_OK, response, 10000, AT_COMMAND); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return -1; - } + command = sara_r5_calloc_char(strlen(SARA_R5_SIGNAL_QUALITY) + 1); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s", SARA_R5_SIGNAL_QUALITY); - if (sscanf(response, "\r\n+CSQ: %d,%*d", &rssi) != 1) - { - rssi = -1; - } + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } + err = sendCommandWithResponse(command, + SARA_R5_RESPONSE_OK, response, 10000, AT_COMMAND); + if (err != SARA_R5_ERROR_SUCCESS) + { free(command); free(response); - return rssi; + return -1; + } + + if (sscanf(response, "\r\n+CSQ: %d,%*d", &rssi) != 1) + { + rssi = -1; + } + + free(command); + free(response); + return rssi; } SARA_R5_registration_status_t SARA_R5::registration(void) { - char *command; - char *response; - SARA_R5_error_t err; - int status; - - command = sara_r5_calloc_char(strlen(SARA_R5_REGISTRATION_STATUS) + 2); - if (command == NULL) - return SARA_R5_REGISTRATION_INVALID; - sprintf(command, "%s?", SARA_R5_REGISTRATION_STATUS); + char *command; + char *response; + SARA_R5_error_t err; + int status; - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return SARA_R5_REGISTRATION_INVALID; - } + command = sara_r5_calloc_char(strlen(SARA_R5_REGISTRATION_STATUS) + 2); + if (command == NULL) + return SARA_R5_REGISTRATION_INVALID; + sprintf(command, "%s?", SARA_R5_REGISTRATION_STATUS); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT, AT_COMMAND); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return SARA_R5_REGISTRATION_INVALID; - } + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return SARA_R5_REGISTRATION_INVALID; + } - if (sscanf(response, "\r\n+CREG: %*d,%d", &status) != 1) - { - status = SARA_R5_REGISTRATION_INVALID; - } + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT, AT_COMMAND); + if (err != SARA_R5_ERROR_SUCCESS) + { free(command); free(response); - return (SARA_R5_registration_status_t)status; + return SARA_R5_REGISTRATION_INVALID; + } + + if (sscanf(response, "\r\n+CREG: %*d,%d", &status) != 1) + { + status = SARA_R5_REGISTRATION_INVALID; + } + free(command); + free(response); + return (SARA_R5_registration_status_t)status; } bool SARA_R5::setNetworkProfile(mobile_network_operator_t mno, bool autoReset, bool urcNotification) { - mobile_network_operator_t currentMno; + mobile_network_operator_t currentMno; - // Check currently set MNO profile - if (getMNOprofile(¤tMno) != SARA_R5_ERROR_SUCCESS) - { - return false; - } + // Check currently set MNO profile + if (getMNOprofile(¤tMno) != SARA_R5_ERROR_SUCCESS) + { + return false; + } - if (currentMno == mno) - { - return true; - } + if (currentMno == mno) + { + return true; + } - // Disable transmit and receive so we can change operator - if (functionality(MINIMUM_FUNCTIONALITY) != SARA_R5_ERROR_SUCCESS) - { - return false; - } + // Disable transmit and receive so we can change operator + if (functionality(MINIMUM_FUNCTIONALITY) != SARA_R5_ERROR_SUCCESS) + { + return false; + } - if (setMNOprofile(mno, autoReset, urcNotification) != SARA_R5_ERROR_SUCCESS) - { - return false; - } + if (setMNOprofile(mno, autoReset, urcNotification) != SARA_R5_ERROR_SUCCESS) + { + return false; + } - if (reset() != SARA_R5_ERROR_SUCCESS) - { - return false; - } + if (reset() != SARA_R5_ERROR_SUCCESS) + { + return false; + } - return true; + return true; } mobile_network_operator_t SARA_R5::getNetworkProfile(void) { - mobile_network_operator_t mno; - SARA_R5_error_t err; + mobile_network_operator_t mno; + SARA_R5_error_t err; - err = getMNOprofile(&mno); - if (err != SARA_R5_ERROR_SUCCESS) - { - return MNO_INVALID; - } - return mno; + err = getMNOprofile(&mno); + if (err != SARA_R5_ERROR_SUCCESS) + { + return MNO_INVALID; + } + return mno; } SARA_R5_error_t SARA_R5::setAPN(String apn, uint8_t cid, SARA_R5_pdp_type pdpType) { - SARA_R5_error_t err; - char *command; - char pdpStr[8]; + SARA_R5_error_t err; + char *command; + char pdpStr[8]; - memset(pdpStr, 0, 8); + memset(pdpStr, 0, 8); - if (cid >= 8) - return SARA_R5_ERROR_UNEXPECTED_PARAM; + if (cid >= 8) + return SARA_R5_ERROR_UNEXPECTED_PARAM; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_DEF) + strlen(apn.c_str()) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - switch (pdpType) - { - case PDP_TYPE_INVALID: - free(command); - return SARA_R5_ERROR_UNEXPECTED_PARAM; - break; - case PDP_TYPE_IP: - memcpy(pdpStr, "IP", 2); - break; - case PDP_TYPE_NONIP: - memcpy(pdpStr, "NONIP", 2); - break; - case PDP_TYPE_IPV4V6: - memcpy(pdpStr, "IPV4V6", 2); - break; - case PDP_TYPE_IPV6: - memcpy(pdpStr, "IPV6", 2); - break; - default: - free(command); - return SARA_R5_ERROR_UNEXPECTED_PARAM; - break; - } - if (apn == NULL) - { - if (_printDebug == true) _debugPort->println("APN: NULL"); - sprintf(command, "%s=%d,\"%s\",\"\"", SARA_R5_MESSAGE_PDP_DEF, + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_DEF) + strlen(apn.c_str()) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + switch (pdpType) + { + case PDP_TYPE_INVALID: + free(command); + return SARA_R5_ERROR_UNEXPECTED_PARAM; + break; + case PDP_TYPE_IP: + memcpy(pdpStr, "IP", 2); + break; + case PDP_TYPE_NONIP: + memcpy(pdpStr, "NONIP", 2); + break; + case PDP_TYPE_IPV4V6: + memcpy(pdpStr, "IPV4V6", 2); + break; + case PDP_TYPE_IPV6: + memcpy(pdpStr, "IPV6", 2); + break; + default: + free(command); + return SARA_R5_ERROR_UNEXPECTED_PARAM; + break; + } + if (apn == NULL) + { + if (_printDebug == true) + _debugPort->println(F("setAPN: NULL")); + sprintf(command, "%s=%d,\"%s\",\"\"", SARA_R5_MESSAGE_PDP_DEF, cid, pdpStr); - } - else + } + else + { + if (_printDebug == true) { - if (_printDebug == true) _debugPort->println("APN: " + ((String)apn)); - sprintf(command, "%s=%d,\"%s\",\"%s\"", SARA_R5_MESSAGE_PDP_DEF, - cid, pdpStr, apn.c_str()); + _debugPort->print(F("setAPN: ")); + _debugPort->println(apn); } + sprintf(command, "%s=%d,\"%s\",\"%s\"", SARA_R5_MESSAGE_PDP_DEF, + cid, pdpStr, apn.c_str()); + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); + free(command); - return err; + return err; } // Return the Access Point Name and IP address for the chosen context identifier SARA_R5_error_t SARA_R5::getAPN(int cid, String *apn, IPAddress *ip) { - SARA_R5_error_t err; - char *command; - char *response; - int ipOctets[4]; - int rcid = -1; + SARA_R5_error_t err; + char *command; + char *response; + int ipOctets[4]; + int rcid = -1; - if (cid > SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS) - return SARA_R5_ERROR_ERROR; + if (cid > SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_DEF) + 3); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_MESSAGE_PDP_DEF); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_DEF) + 3); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_MESSAGE_PDP_DEF); - response = sara_r5_calloc_char(1024); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(1024); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) - { - // Example: - // +CGDCONT: 0,"IP","payandgo.o2.co.uk","0.0.0.0",0,0,0,0,0,0,0,0,0,0 - // +CGDCONT: 1,"IP","payandgo.o2.co.uk.mnc010.mcc234.gprs","10.160.182.234",0,0,0,2,0,0,0,0,0,0 + if (err == SARA_R5_ERROR_SUCCESS) + { + // Example: + // +CGDCONT: 0,"IP","payandgo.o2.co.uk","0.0.0.0",0,0,0,0,0,0,0,0,0,0 + // +CGDCONT: 1,"IP","payandgo.o2.co.uk.mnc010.mcc234.gprs","10.160.182.234",0,0,0,2,0,0,0,0,0,0 - char *searchPtr = response; + char *searchPtr = response; - bool keepGoing = true; - while (keepGoing == true) + bool keepGoing = true; + while (keepGoing == true) + { + int apnLen = 0; + int scanned = 0; + // Find the first/next occurrence of +CGDCONT: + searchPtr = strstr(searchPtr, "+CGDCONT: "); + if (searchPtr != NULL) { - int apnLen = 0; - int scanned = 0; - // Find the first/next occurrence of +CGDCONT: - searchPtr = strstr(searchPtr, "+CGDCONT: "); - if (searchPtr != NULL) + searchPtr += strlen("+CGDCONT: "); // Point to the cid + rcid = (*searchPtr) - '0'; // Get the first/only digit of cid + searchPtr++; + if (*searchPtr != ',') // Get the second digit of cid - if there is one + { + rcid *= 10; + rcid += (*searchPtr) - '0'; + } + if (_printDebug == true) + { + _debugPort->print(F("getAPN: cid is ")); + _debugPort->println(rcid); + } + if (rcid == cid) // If we have a match { - searchPtr += strlen("+CGDCONT: "); // Point to the cid - rcid = (*searchPtr) - '0'; // Get the first/only digit of cid - searchPtr++; - if (*searchPtr != ',') // Get the second digit of cid - if there is one + // Search to the third double-quote + for (int i = 0; i < 3; i++) { - rcid *= 10; - rcid += (*searchPtr) - '0'; + searchPtr = strchr(++searchPtr, '\"'); } - if (_printDebug == true) _debugPort->println("getAPN: cid is " + ((String)rcid)); - if (rcid == cid) // If we have a match + if (searchPtr != NULL) { - // Search to the third double-quote - for (int i = 0; i < 3; i++) + // Fill in the APN: + //searchPtr = strchr(searchPtr, '\"'); // Move to first quote + while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) { - searchPtr = strchr(++searchPtr, '\"'); + apn->concat(*(searchPtr)); + apnLen++; } + // Now get the IP: if (searchPtr != NULL) { - // Fill in the APN: - //searchPtr = strchr(searchPtr, '\"'); // Move to first quote - while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) + scanned = sscanf(searchPtr, "\",\"%d.%d.%d.%d\"", + &ipOctets[0], &ipOctets[1], &ipOctets[2], &ipOctets[3]); + if (scanned == 4) + { + for (int octet = 0; octet < 4; octet++) { - apn->concat(*(searchPtr)); - apnLen++; - } - // Now get the IP: - if (searchPtr != NULL) - { - scanned = sscanf(searchPtr, "\",\"%d.%d.%d.%d\"", - &ipOctets[0], &ipOctets[1], &ipOctets[2], &ipOctets[3]); - if (scanned == 4) - { - for (int octet = 0; octet < 4; octet++) - { - (*ip)[octet] = (uint8_t)ipOctets[octet]; - } - } + (*ip)[octet] = (uint8_t)ipOctets[octet]; } + } } } - else // We don't have a match so let's clear the APN and IP address - { - *apn = ""; - *ip = {0,0,0,0}; - } } - if ((rcid == cid) || (searchPtr == NULL) || (*searchPtr == '\0')) // Stop searching + else // We don't have a match so let's clear the APN and IP address { - keepGoing = false; + *apn = ""; + *ip = {0, 0, 0, 0}; } } + if ((rcid == cid) || (searchPtr == NULL) || (*searchPtr == '\0')) // Stop searching + { + keepGoing = false; + } } - else - { - err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } + } + else + { + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - free(command); - free(response); + free(command); + free(response); - return err; + return err; } SARA_R5_error_t SARA_R5::setSIMstateReportingMode(int mode) @@ -1404,7 +1412,7 @@ SARA_R5_error_t SARA_R5::setSIMstateReportingMode(int mode) command = sara_r5_calloc_char(strlen(SARA_R5_SIM_STATE) + 4); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s=%d", SARA_R5_SIM_STATE, mode); err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -1423,14 +1431,14 @@ SARA_R5_error_t SARA_R5::getSIMstateReportingMode(int *mode) command = sara_r5_calloc_char(strlen(SARA_R5_SIM_STATE) + 3); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s?", SARA_R5_SIM_STATE); response = sara_r5_calloc_char(48); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -1438,12 +1446,13 @@ SARA_R5_error_t SARA_R5::getSIMstateReportingMode(int *mode) if (err == SARA_R5_ERROR_SUCCESS) { - int scanned = sscanf(response, "\r\n+USIMSTAT: %d\r\n", &m); - if (scanned == 1) - { - *mode = m; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + int scanned = sscanf(response, "\r\n+USIMSTAT: %d\r\n", &m); + if (scanned == 1) + { + *mode = m; + } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -1460,353 +1469,357 @@ const char *PPP_L2P[5] = { }; SARA_R5_error_t SARA_R5::enterPPP(uint8_t cid, char dialing_type_char, - unsigned long dialNumber, SARA_R5::SARA_R5_l2p_t l2p) + unsigned long dialNumber, SARA_R5::SARA_R5_l2p_t l2p) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if ((dialing_type_char != 0) && (dialing_type_char != 'T') && - (dialing_type_char != 'P')) - { - return SARA_R5_ERROR_UNEXPECTED_PARAM; - } + if ((dialing_type_char != 0) && (dialing_type_char != 'T') && + (dialing_type_char != 'P')) + { + return SARA_R5_ERROR_UNEXPECTED_PARAM; + } - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_ENTER_PPP) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (dialing_type_char != 0) - { - sprintf(command, "%s%c*%lu**%s*%u#", SARA_R5_MESSAGE_ENTER_PPP, dialing_type_char, - dialNumber, PPP_L2P[l2p], (unsigned int)cid); - } - else - { - sprintf(command, "%s*%lu**%s*%u#", SARA_R5_MESSAGE_ENTER_PPP, - dialNumber, PPP_L2P[l2p], (unsigned int)cid); - } + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_ENTER_PPP) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (dialing_type_char != 0) + { + sprintf(command, "%s%c*%lu**%s*%u#", SARA_R5_MESSAGE_ENTER_PPP, dialing_type_char, + dialNumber, PPP_L2P[l2p], (unsigned int)cid); + } + else + { + sprintf(command, "%s*%lu**%s*%u#", SARA_R5_MESSAGE_ENTER_PPP, + dialNumber, PPP_L2P[l2p], (unsigned int)cid); + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_CONNECT, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_CONNECT, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } uint8_t SARA_R5::getOperators(struct operator_stats *opRet, int maxOps) { - SARA_R5_error_t err; - char *command; - char *response; - uint8_t opsSeen = 0; + SARA_R5_error_t err; + char *command; + char *response; + uint8_t opsSeen = 0; - command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 3); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=?", SARA_R5_OPERATOR_SELECTION); + command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 3); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=?", SARA_R5_OPERATOR_SELECTION); - response = sara_r5_calloc_char((maxOps + 1) * 48); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char((maxOps + 1) * 48); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - // AT+COPS maximum response time is 3 minutes (180000 ms) - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_3_MIN_TIMEOUT); + // AT+COPS maximum response time is 3 minutes (180000 ms) + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_3_MIN_TIMEOUT); - // Sample responses: - // +COPS: (3,"Verizon Wireless","VzW","311480",8),,(0,1,2,3,4),(0,1,2) - // +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) + // Sample responses: + // +COPS: (3,"Verizon Wireless","VzW","311480",8),,(0,1,2,3,4),(0,1,2) + // +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) - if (_printDebug == true) - { - _debugPort->print("getOperators: Response: {"); - _debugPort->print(response); - _debugPort->println("}"); - } + if (_printDebug == true) + { + _debugPort->print(F("getOperators: Response: {")); + _debugPort->print(response); + _debugPort->println(F("}")); + } + + if (err == SARA_R5_ERROR_SUCCESS) + { + char *opBegin; + char *opEnd; + int op = 0; + int stat; + char longOp[26]; + char shortOp[11]; + int act; + unsigned long numOp; - if (err == SARA_R5_ERROR_SUCCESS) + opBegin = response; + + for (; op < maxOps; op++) { - char *opBegin; - char *opEnd; - int op = 0; - int stat; - char longOp[26]; - char shortOp[11]; - int act; - unsigned long numOp; - - opBegin = response; - - for (; op < maxOps; op++) - { - opBegin = strchr(opBegin, '('); - if (opBegin == NULL) - break; - opEnd = strchr(opBegin, ')'); - if (opEnd == NULL) - break; - - int sscanRead = sscanf(opBegin, "(%d,\"%[^\"]\",\"%[^\"]\",\"%lu\",%d)%*s", - &stat, longOp, shortOp, &numOp, &act); - if (sscanRead == 5) - { - opRet[op].stat = stat; - opRet[op].longOp = (String)(longOp); - opRet[op].shortOp = (String)(shortOp); - opRet[op].numOp = numOp; - opRet[op].act = act; - opsSeen += 1; - } - // TODO: Search for other possible patterns here - else - { - break; // Break out if pattern doesn't match. - } - opBegin = opEnd + 1; // Move opBegin to beginning of next value - } + opBegin = strchr(opBegin, '('); + if (opBegin == NULL) + break; + opEnd = strchr(opBegin, ')'); + if (opEnd == NULL) + break; + + int sscanRead = sscanf(opBegin, "(%d,\"%[^\"]\",\"%[^\"]\",\"%lu\",%d)%*s", + &stat, longOp, shortOp, &numOp, &act); + if (sscanRead == 5) + { + opRet[op].stat = stat; + opRet[op].longOp = (String)(longOp); + opRet[op].shortOp = (String)(shortOp); + opRet[op].numOp = numOp; + opRet[op].act = act; + opsSeen += 1; + } + // TODO: Search for other possible patterns here + else + { + break; // Break out if pattern doesn't match. + } + opBegin = opEnd + 1; // Move opBegin to beginning of next value } + } - free(command); - free(response); + free(command); + free(response); - return opsSeen; + return opsSeen; } SARA_R5_error_t SARA_R5::registerOperator(struct operator_stats oper) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 24); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=1,2,\"%lu\"", SARA_R5_OPERATOR_SELECTION, oper.numOp); + command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 24); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=1,2,\"%lu\"", SARA_R5_OPERATOR_SELECTION, oper.numOp); - // AT+COPS maximum response time is 3 minutes (180000 ms) - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_3_MIN_TIMEOUT); + // AT+COPS maximum response time is 3 minutes (180000 ms) + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_3_MIN_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::automaticOperatorSelection() { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 6); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=0,0", SARA_R5_OPERATOR_SELECTION); + command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 6); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=0,0", SARA_R5_OPERATOR_SELECTION); - // AT+COPS maximum response time is 3 minutes (180000 ms) - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_3_MIN_TIMEOUT); + // AT+COPS maximum response time is 3 minutes (180000 ms) + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_3_MIN_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::getOperator(String *oper) { - SARA_R5_error_t err; - char *command; - char *response; - char *searchPtr; - char mode; + SARA_R5_error_t err; + char *command; + char *response; + char *searchPtr; + char mode; - command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 3); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_OPERATOR_SELECTION); + command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 3); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_OPERATOR_SELECTION); - response = sara_r5_calloc_char(64); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(64); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - // AT+COPS maximum response time is 3 minutes (180000 ms) - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_3_MIN_TIMEOUT); + // AT+COPS maximum response time is 3 minutes (180000 ms) + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_3_MIN_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + if (err == SARA_R5_ERROR_SUCCESS) + { + searchPtr = strstr(response, "+COPS: "); + if (searchPtr != NULL) { - searchPtr = strstr(response, "+COPS: "); - if (searchPtr != NULL) + searchPtr += strlen("+COPS: "); // Move searchPtr to first char + mode = *searchPtr; // Read first char -- should be mode + if (mode == '2') // Check for de-register + { + err = SARA_R5_ERROR_DEREGISTERED; + } + // Otherwise if it's default, manual, set-only, or automatic + else if ((mode == '0') || (mode == '1') || (mode == '3') || (mode == '4')) + { + *oper = ""; + searchPtr = strchr(searchPtr, '\"'); // Move to first quote + if (searchPtr == NULL) { - searchPtr += strlen("+COPS: "); // Move searchPtr to first char - mode = *searchPtr; // Read first char -- should be mode - if (mode == '2') // Check for de-register - { - err = SARA_R5_ERROR_DEREGISTERED; - } - // Otherwise if it's default, manual, set-only, or automatic - else if ((mode == '0') || (mode == '1') || (mode == '3') || (mode == '4')) - { - *oper = ""; - searchPtr = strchr(searchPtr, '\"'); // Move to first quote - if (searchPtr == NULL) - { - err = SARA_R5_ERROR_DEREGISTERED; - } - else - { - while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) - { - oper->concat(*(searchPtr)); - } - } - if (_printDebug == true) _debugPort->println("Operator: " + *oper); - //oper->concat('\0'); - } + err = SARA_R5_ERROR_DEREGISTERED; + } + else + { + while ((*(++searchPtr) != '\"') && (*searchPtr != '\0')) + { + oper->concat(*(searchPtr)); + } + } + if (_printDebug == true) + { + _debugPort->print(F("getOperator: ")); + _debugPort->println(*oper); } + //oper->concat('\0'); + } } + } - free(response); - free(command); - return err; + free(response); + free(command); + return err; } SARA_R5_error_t SARA_R5::deregisterOperator(void) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 4); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=2", SARA_R5_OPERATOR_SELECTION); + command = sara_r5_calloc_char(strlen(SARA_R5_OPERATOR_SELECTION) + 4); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=2", SARA_R5_OPERATOR_SELECTION); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_3_MIN_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_3_MIN_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setSMSMessageFormat(SARA_R5_message_format_t textMode) { - char *command; - SARA_R5_error_t err; + char *command; + SARA_R5_error_t err; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_FORMAT) + 4); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_MESSAGE_FORMAT, - (textMode == SARA_R5_MESSAGE_FORMAT_TEXT) ? 1 : 0); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_FORMAT) + 4); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_MESSAGE_FORMAT, + (textMode == SARA_R5_MESSAGE_FORMAT_TEXT) ? 1 : 0); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::sendSMS(String number, String message) { - char *command; - char *messageCStr; - char *numberCStr; - SARA_R5_error_t err; - - numberCStr = sara_r5_calloc_char(number.length() + 2); - if (numberCStr == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - number.toCharArray(numberCStr, number.length() + 1); - - command = sara_r5_calloc_char(strlen(SARA_R5_SEND_TEXT) + strlen(numberCStr) + 8); - if (command != NULL) - { - sprintf(command, "%s=\"%s\"", SARA_R5_SEND_TEXT, numberCStr); + char *command; + char *messageCStr; + char *numberCStr; + SARA_R5_error_t err; - err = sendCommandWithResponse(command, ">", NULL, - SARA_R5_3_MIN_TIMEOUT); - free(command); - free(numberCStr); - if (err != SARA_R5_ERROR_SUCCESS) - return err; + numberCStr = sara_r5_calloc_char(number.length() + 2); + if (numberCStr == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + number.toCharArray(numberCStr, number.length() + 1); - messageCStr = sara_r5_calloc_char(message.length() + 1); - if (messageCStr == NULL) - { - hwWrite(ASCII_CTRL_Z); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } - message.toCharArray(messageCStr, message.length() + 1); - messageCStr[message.length()] = ASCII_CTRL_Z; + command = sara_r5_calloc_char(strlen(SARA_R5_SEND_TEXT) + strlen(numberCStr) + 8); + if (command != NULL) + { + sprintf(command, "%s=\"%s\"", SARA_R5_SEND_TEXT, numberCStr); - err = sendCommandWithResponse(messageCStr, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_3_MIN_TIMEOUT, NOT_AT_COMMAND); + err = sendCommandWithResponse(command, ">", NULL, + SARA_R5_3_MIN_TIMEOUT); + free(command); + free(numberCStr); + if (err != SARA_R5_ERROR_SUCCESS) + return err; - free(messageCStr); - } - else + messageCStr = sara_r5_calloc_char(message.length() + 1); + if (messageCStr == NULL) { - free(numberCStr); - err = SARA_R5_ERROR_OUT_OF_MEMORY; + hwWrite(ASCII_CTRL_Z); + return SARA_R5_ERROR_OUT_OF_MEMORY; } + message.toCharArray(messageCStr, message.length() + 1); + messageCStr[message.length()] = ASCII_CTRL_Z; - return err; + err = sendCommandWithResponse(messageCStr, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_3_MIN_TIMEOUT, NOT_AT_COMMAND); + + free(messageCStr); + } + else + { + free(numberCStr); + err = SARA_R5_ERROR_OUT_OF_MEMORY; + } + + return err; } SARA_R5_error_t SARA_R5::getPreferredMessageStorage(int *used, int *total, String memory) { - SARA_R5_error_t err; - char *command; - char *response; - int u; - int t; + SARA_R5_error_t err; + char *command; + char *response; + int u; + int t; - command = sara_r5_calloc_char(strlen(SARA_R5_PREF_MESSAGE_STORE) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=\"%s\"", SARA_R5_PREF_MESSAGE_STORE, memory.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_PREF_MESSAGE_STORE) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=\"%s\"", SARA_R5_PREF_MESSAGE_STORE, memory.c_str()); - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_3_MIN_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_3_MIN_TIMEOUT); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return err; - } + if (err != SARA_R5_ERROR_SUCCESS) + { + free(command); + free(response); + return err; + } - int ret = sscanf(response, "\r\n+CPMS: %d,%d", &u, &t); - if (ret == 2) - { - if (_printDebug == true) - { - _debugPort->print("getPreferredMessageStorage: memory: "); - _debugPort->print(memory); - _debugPort->print(" used: "); - _debugPort->print(u); - _debugPort->print(" total: "); - _debugPort->println(t); - } - *used = u; - *total = t; - } - else + int ret = sscanf(response, "\r\n+CPMS: %d,%d", &u, &t); + if (ret == 2) + { + if (_printDebug == true) { - err = SARA_R5_ERROR_INVALID; + _debugPort->print(F("getPreferredMessageStorage: memory: ")); + _debugPort->print(memory); + _debugPort->print(F(" used: ")); + _debugPort->print(u); + _debugPort->print(F(" total: ")); + _debugPort->println(t); } + *used = u; + *total = t; + } + else + { + err = SARA_R5_ERROR_INVALID; + } - free(response); - free(command); - return err; + free(response); + free(command); + return err; } SARA_R5_error_t SARA_R5::readSMSmessage(int location, String *unread, String *from, String *dateTime, String *message) @@ -1817,14 +1830,14 @@ SARA_R5_error_t SARA_R5::readSMSmessage(int location, String *unread, String *fr command = sara_r5_calloc_char(strlen(SARA_R5_READ_TEXT_MESSAGE) + 5); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s=%d", SARA_R5_READ_TEXT_MESSAGE, location); response = sara_r5_calloc_char(1024); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, @@ -1904,7 +1917,7 @@ SARA_R5_error_t SARA_R5::readSMSmessage(int location, String *unread, String *fr } else { - err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -1915,822 +1928,839 @@ SARA_R5_error_t SARA_R5::readSMSmessage(int location, String *unread, String *fr SARA_R5_error_t SARA_R5::setBaud(unsigned long baud) { - SARA_R5_error_t err; - char *command; - int b = 0; + SARA_R5_error_t err; + char *command; + int b = 0; - // Error check -- ensure supported baud - for (; b < NUM_SUPPORTED_BAUD; b++) - { - if (SARA_R5_SUPPORTED_BAUD[b] == baud) - { - break; - } - } - if (b >= NUM_SUPPORTED_BAUD) + // Error check -- ensure supported baud + for (; b < NUM_SUPPORTED_BAUD; b++) + { + if (SARA_R5_SUPPORTED_BAUD[b] == baud) { - return SARA_R5_ERROR_UNEXPECTED_PARAM; + break; } + } + if (b >= NUM_SUPPORTED_BAUD) + { + return SARA_R5_ERROR_UNEXPECTED_PARAM; + } - // Construct command - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_BAUD) + 7 + 12); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%lu", SARA_R5_COMMAND_BAUD, baud); + // Construct command + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_BAUD) + 7 + 12); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%lu", SARA_R5_COMMAND_BAUD, baud); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_SET_BAUD_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_SET_BAUD_TIMEOUT); - free(command); + free(command); - return err; + return err; } SARA_R5_error_t SARA_R5::setFlowControl(SARA_R5_flow_control_t value) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_FLOW_CONTROL) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s%d", SARA_R5_FLOW_CONTROL, value); + command = sara_r5_calloc_char(strlen(SARA_R5_FLOW_CONTROL) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s%d", SARA_R5_FLOW_CONTROL, value); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); + free(command); - return err; + return err; } SARA_R5_error_t SARA_R5::setGpioMode(SARA_R5_gpio_t gpio, - SARA_R5_gpio_mode_t mode, int value) -{ - SARA_R5_error_t err; - char *command; - - // Example command: AT+UGPIOC=16,2 - // Example command: AT+UGPIOC=23,0,1 - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_GPIO) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (mode == GPIO_OUTPUT) - sprintf(command, "%s=%d,%d,%d", SARA_R5_COMMAND_GPIO, gpio, mode, value); - else - sprintf(command, "%s=%d,%d", SARA_R5_COMMAND_GPIO, gpio, mode); + SARA_R5_gpio_mode_t mode, int value) +{ + SARA_R5_error_t err; + char *command; - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_10_SEC_TIMEOUT); + // Example command: AT+UGPIOC=16,2 + // Example command: AT+UGPIOC=23,0,1 + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_GPIO) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (mode == GPIO_OUTPUT) + sprintf(command, "%s=%d,%d,%d", SARA_R5_COMMAND_GPIO, gpio, mode, value); + else + sprintf(command, "%s=%d,%d", SARA_R5_COMMAND_GPIO, gpio, mode); - free(command); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_10_SEC_TIMEOUT); - return err; + free(command); + + return err; } SARA_R5::SARA_R5_gpio_mode_t SARA_R5::getGpioMode(SARA_R5_gpio_t gpio) { - SARA_R5_error_t err; - char *command; - char *response; - char gpioChar[4]; - char *gpioStart; - int gpioMode; - - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_GPIO) + 2); - if (command == NULL) - return GPIO_MODE_INVALID; - sprintf(command, "%s?", SARA_R5_COMMAND_GPIO); - - response = sara_r5_calloc_char(96); - if (response == NULL) - { - free(command); - return GPIO_MODE_INVALID; - } + SARA_R5_error_t err; + char *command; + char *response; + char gpioChar[4]; + char *gpioStart; + int gpioMode; - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_GPIO) + 2); + if (command == NULL) + return GPIO_MODE_INVALID; + sprintf(command, "%s?", SARA_R5_COMMAND_GPIO); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return GPIO_MODE_INVALID; - } + response = sara_r5_calloc_char(96); + if (response == NULL) + { + free(command); + return GPIO_MODE_INVALID; + } - sprintf(gpioChar, "%d", gpio); // Convert GPIO to char array - gpioStart = strstr(response, gpioChar); // Find first occurence of GPIO in response + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err != SARA_R5_ERROR_SUCCESS) + { free(command); free(response); + return GPIO_MODE_INVALID; + } + + sprintf(gpioChar, "%d", gpio); // Convert GPIO to char array + gpioStart = strstr(response, gpioChar); // Find first occurence of GPIO in response - if (gpioStart == NULL) - return GPIO_MODE_INVALID; // If not found return invalid - sscanf(gpioStart, "%*d,%d\r\n", &gpioMode); + free(command); + free(response); - return (SARA_R5_gpio_mode_t)gpioMode; + if (gpioStart == NULL) + return GPIO_MODE_INVALID; // If not found return invalid + sscanf(gpioStart, "%*d,%d\r\n", &gpioMode); + + return (SARA_R5_gpio_mode_t)gpioMode; } int SARA_R5::socketOpen(SARA_R5_socket_protocol_t protocol, unsigned int localPort) { - SARA_R5_error_t err; - char *command; - char *response; - int sockId = -1; - char *responseStart; + SARA_R5_error_t err; + char *command; + char *response; + int sockId = -1; + char *responseStart; - command = sara_r5_calloc_char(strlen(SARA_R5_CREATE_SOCKET) + 10); - if (command == NULL) - return -1; + command = sara_r5_calloc_char(strlen(SARA_R5_CREATE_SOCKET) + 10); + if (command == NULL) + return -1; + if (localPort == 0) + sprintf(command, "%s=%d", SARA_R5_CREATE_SOCKET, protocol); + else sprintf(command, "%s=%d,%d", SARA_R5_CREATE_SOCKET, protocol, localPort); - response = sara_r5_calloc_char(128); - if (response == NULL) - { - if (_printDebug == true) _debugPort->println("Socket Open Failure: NULL response."); - free(command); - return -1; - } + response = sara_r5_calloc_char(128); + if (response == NULL) + { + if (_printDebug == true) + _debugPort->println(F("socketOpen: Fail: NULL response")); + free(command); + return -1; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err != SARA_R5_ERROR_SUCCESS) + if (err != SARA_R5_ERROR_SUCCESS) + { + if (_printDebug == true) { - if (_printDebug == true) - { - _debugPort->print("Socket Open Failure: "); - _debugPort->println(err); - _debugPort->println("Response: {"); - _debugPort->println(response); - _debugPort->println("}"); - } - free(command); - free(response); - return -1; + _debugPort->print(F("socketOpen: Fail: Error: ")); + _debugPort->print(err); + _debugPort->print(F(" Response: {")); + _debugPort->print(response); + _debugPort->println(F("}")); } + free(command); + free(response); + return -1; + } - responseStart = strstr(response, "+USOCR"); - if (responseStart == NULL) + responseStart = strstr(response, "+USOCR"); + if (responseStart == NULL) + { + if (_printDebug == true) { - if (_printDebug == true) - { - _debugPort->print("Socket Open Failure: {"); - _debugPort->print(response); - _debugPort->println("}"); - } - free(command); - free(response); - return -1; + _debugPort->print(F("socketOpen: Failure: {")); + _debugPort->print(response); + _debugPort->println(F("}")); } - - sscanf(responseStart, "+USOCR: %d", &sockId); - free(command); free(response); + return -1; + } + + sscanf(responseStart, "+USOCR: %d", &sockId); + + free(command); + free(response); - return sockId; + return sockId; } SARA_R5_error_t SARA_R5::socketClose(int socket, unsigned long timeout) { - SARA_R5_error_t err; - char *command; - char *response; + SARA_R5_error_t err; + char *command; + char *response; - command = sara_r5_calloc_char(strlen(SARA_R5_CLOSE_SOCKET) + 10); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - response = sara_r5_calloc_char(128); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } - sprintf(command, "%s=%d", SARA_R5_CLOSE_SOCKET, socket); + command = sara_r5_calloc_char(strlen(SARA_R5_CLOSE_SOCKET) + 10); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + response = sara_r5_calloc_char(128); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } + sprintf(command, "%s=%d", SARA_R5_CLOSE_SOCKET, socket); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, timeout); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, timeout); - if ((err != SARA_R5_ERROR_SUCCESS) && (_printDebug == true)) - { - _debugPort->print("Socket Close Error Code: "); - _debugPort->println(socketGetLastError()); - } + if ((err != SARA_R5_ERROR_SUCCESS) && (_printDebug == true)) + { + _debugPort->print(F("socketClose: Error: ")); + _debugPort->println(socketGetLastError()); + } - free(command); - free(response); + free(command); + free(response); - return err; + return err; } SARA_R5_error_t SARA_R5::socketConnect(int socket, const char *address, - unsigned int port) + unsigned int port) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_CONNECT_SOCKET) + strlen(address) + 11); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,\"%s\",%d", SARA_R5_CONNECT_SOCKET, socket, address, port); + command = sara_r5_calloc_char(strlen(SARA_R5_CONNECT_SOCKET) + strlen(address) + 11); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,\"%s\",%d", SARA_R5_CONNECT_SOCKET, socket, address, port); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_IP_CONNECT_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_IP_CONNECT_TIMEOUT); - free(command); + free(command); - return err; + return err; } SARA_R5_error_t SARA_R5::socketWrite(int socket, const char *str) { - char *command; - char *response; - SARA_R5_error_t err; - unsigned long writeDelay; + char *command; + char *response; + SARA_R5_error_t err; + unsigned long writeDelay; - command = sara_r5_calloc_char(strlen(SARA_R5_WRITE_SOCKET) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - response = sara_r5_calloc_char(128); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } - sprintf(command, "%s=%d,%d", SARA_R5_WRITE_SOCKET, socket, strlen(str)); + command = sara_r5_calloc_char(strlen(SARA_R5_WRITE_SOCKET) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + response = sara_r5_calloc_char(128); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } + sprintf(command, "%s=%d,%d", SARA_R5_WRITE_SOCKET, socket, strlen(str)); - err = sendCommandWithResponse(command, "@", response, - SARA_R5_2_MIN_TIMEOUT); + err = sendCommandWithResponse(command, "@", response, + SARA_R5_2_MIN_TIMEOUT); + + if (err == SARA_R5_ERROR_SUCCESS) + { + writeDelay = millis(); + while (millis() < (writeDelay + 50)) + ; //uBlox specification says to wait 50ms after receiving "@" to write data. - if (err == SARA_R5_ERROR_SUCCESS) + if (_printDebug == true) { - writeDelay = millis(); - while (millis() < (writeDelay + 50)) - ; //uBlox specification says to wait 50ms after receiving "@" to write data. + _debugPort->print(F("socketWrite: writing: ")); + _debugPort->println(str); + } + hwPrint(str); + err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_SOCKET_WRITE_TIMEOUT); + } - hwPrint(str); - err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_SOCKET_WRITE_TIMEOUT); - } - else + if (err != SARA_R5_ERROR_SUCCESS) + { + if (_printDebug == true) { - if (_printDebug == true) - { - _debugPort->print("WriteCmd Err Response: "); - _debugPort->print(err); - _debugPort->print(" => {"); - _debugPort->print(response); - _debugPort->println("}"); - } - } + _debugPort->print(F("socketWrite: Error: ")); + _debugPort->print(err); + _debugPort->print(F(" => {")); + _debugPort->print(response); + _debugPort->println(F("}")); + } + } - free(command); - free(response); - return err; + free(command); + free(response); + return err; } SARA_R5_error_t SARA_R5::socketWrite(int socket, String str) { - return socketWrite(socket, str.c_str()); + return socketWrite(socket, str.c_str()); } -SARA_R5_error_t SARA_R5::socketWriteUDP(int socket, const char *address, int port, const char *str, int len){ - char *command; - char *response; - SARA_R5_error_t err; - int dataLen = len == -1 ? strlen(str) : len; +SARA_R5_error_t SARA_R5::socketWriteUDP(int socket, const char *address, int port, const char *str, int len) +{ + char *command; + char *response; + SARA_R5_error_t err; + int dataLen = len == -1 ? strlen(str) : len; - command = sara_r5_calloc_char(64); + command = sara_r5_calloc_char(64); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; response = sara_r5_calloc_char(128); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } - sprintf(command, "%s=%d,\"%s\",%d,%d", SARA_R5_WRITE_UDP_SOCKET, - socket, address, port, dataLen); - err = sendCommandWithResponse(command, "@", response, SARA_R5_IP_CONNECT_TIMEOUT); + sprintf(command, "%s=%d,\"%s\",%d,%d", SARA_R5_WRITE_UDP_SOCKET, + socket, address, port, dataLen); + err = sendCommandWithResponse(command, "@", response, SARA_R5_IP_CONNECT_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + if (err == SARA_R5_ERROR_SUCCESS) { - if (len == -1) //If binary data we need to send a length. + if (len == -1) //If binary data we need to send a length. { - hwPrint(str); - } + hwPrint(str); + } else { - hwWriteData(str, len); - } - err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_SOCKET_WRITE_TIMEOUT); - } + hwWriteData(str, len); + } + err = waitForResponse(SARA_R5_RESPONSE_OK, SARA_R5_RESPONSE_ERROR, SARA_R5_SOCKET_WRITE_TIMEOUT); + } else { - if (_printDebug == true) _debugPort->print("UDP Write Error: "); - if (_printDebug == true) _debugPort->println(socketGetLastError()); - } + if (_printDebug == true) + _debugPort->print(F("socketWriteUDP: Error: ")); + if (_printDebug == true) + _debugPort->println(socketGetLastError()); + } - free(command); - free(response); - return err; + free(command); + free(response); + return err; } -SARA_R5_error_t SARA_R5::socketWriteUDP(int socket, String address, int port, String str, int len){ - return socketWriteUDP(socket, address.c_str(), port, str.c_str(), len); +SARA_R5_error_t SARA_R5::socketWriteUDP(int socket, String address, int port, String str, int len) +{ + return socketWriteUDP(socket, address.c_str(), port, str.c_str(), len); } SARA_R5_error_t SARA_R5::socketRead(int socket, int length, char *readDest) { - char *command; - char *response; - char *strBegin; - int readIndex = 0; - SARA_R5_error_t err; + char *command; + char *response; + char *strBegin; + int readIndex = 0; + SARA_R5_error_t err; - command = sara_r5_calloc_char(strlen(SARA_R5_READ_SOCKET) + 8); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d", SARA_R5_READ_SOCKET, socket, length); + command = sara_r5_calloc_char(strlen(SARA_R5_READ_SOCKET) + 8); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d", SARA_R5_READ_SOCKET, socket, length); - response = sara_r5_calloc_char(length + strlen(SARA_R5_READ_SOCKET) + 128); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(length + strlen(SARA_R5_READ_SOCKET) + 128); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) - { - // Find the first double-quote: - strBegin = strchr(response, '\"'); + if (err == SARA_R5_ERROR_SUCCESS) + { + // Find the first double-quote: + strBegin = strchr(response, '\"'); - if (strBegin == NULL) - { - free(command); - free(response); - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } + if (strBegin == NULL) + { + free(command); + free(response); + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - while ((readIndex < length) && (readIndex < (int)strlen(strBegin))) - { - readDest[readIndex] = strBegin[1 + readIndex]; - readIndex += 1; - } + while ((readIndex < length) && (readIndex < (int)strlen(strBegin))) + { + readDest[readIndex] = strBegin[1 + readIndex]; + readIndex += 1; } + } - free(command); - free(response); + free(command); + free(response); - return err; + return err; } SARA_R5_error_t SARA_R5::socketReadUDP(int socket, int length, char *readDest) { - char *command; - char *response; - char *strBegin; - int readIndex = 0; - SARA_R5_error_t err; + char *command; + char *response; + char *strBegin; + int readIndex = 0; + SARA_R5_error_t err; - command = sara_r5_calloc_char(strlen(SARA_R5_READ_UDP_SOCKET) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d", SARA_R5_READ_UDP_SOCKET, socket, length); + command = sara_r5_calloc_char(strlen(SARA_R5_READ_UDP_SOCKET) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d", SARA_R5_READ_UDP_SOCKET, socket, length); - response = sara_r5_calloc_char(length + strlen(SARA_R5_READ_UDP_SOCKET) + 128); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(length + strlen(SARA_R5_READ_UDP_SOCKET) + 128); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) - { - // Find the third double-quote. This needs to be improved to collect other data. - if (_printDebug == true) _debugPort->print("UDP READ: {"); - if (_printDebug == true) _debugPort->print(response); - if (_printDebug == true) _debugPort->println("}"); + if (err == SARA_R5_ERROR_SUCCESS) + { + // Find the third double-quote. This needs to be improved to collect other data. + if (_printDebug == true) + _debugPort->print(F("socketReadUDP: {")); + if (_printDebug == true) + _debugPort->print(response); + if (_printDebug == true) + _debugPort->println(F("}")); - strBegin = strchr(response, '\"'); - strBegin = strchr(strBegin+1, '\"'); - strBegin = strchr(strBegin+1, '\"'); + strBegin = strchr(response, '\"'); + strBegin = strchr(strBegin + 1, '\"'); + strBegin = strchr(strBegin + 1, '\"'); - if (strBegin == NULL) - { - free(command); - free(response); - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } + if (strBegin == NULL) + { + free(command); + free(response); + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - while ((readIndex < length) && (readIndex < (int)strlen(strBegin))) - { - readDest[readIndex] = strBegin[1 + readIndex]; - readIndex += 1; - } + while ((readIndex < length) && (readIndex < (int)strlen(strBegin))) + { + readDest[readIndex] = strBegin[1 + readIndex]; + readIndex += 1; } + } - free(command); - free(response); + free(command); + free(response); - return err; + return err; } SARA_R5_error_t SARA_R5::socketListen(int socket, unsigned int port) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_LISTEN_SOCKET) + 9); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d", SARA_R5_LISTEN_SOCKET, socket, port); + command = sara_r5_calloc_char(strlen(SARA_R5_LISTEN_SOCKET) + 9); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d", SARA_R5_LISTEN_SOCKET, socket, port); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::socketDirectLinkMode(int socket) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_SOCKET_DIRECT_LINK) + 8); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_SOCKET_DIRECT_LINK, socket); + command = sara_r5_calloc_char(strlen(SARA_R5_SOCKET_DIRECT_LINK) + 8); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_SOCKET_DIRECT_LINK, socket); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_CONNECT, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_CONNECT, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::socketDirectLinkTimeTrigger(int socket, unsigned long timerTrigger) { - // valid range is 0 (trigger disabled), 100-120000 - if (!((timerTrigger == 0) || ((timerTrigger >= 100) && (timerTrigger <= 120000)))) - return SARA_R5_ERROR_ERROR; + // valid range is 0 (trigger disabled), 100-120000 + if (!((timerTrigger == 0) || ((timerTrigger >= 100) && (timerTrigger <= 120000)))) + return SARA_R5_ERROR_ERROR; - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=5,%d,%ld", SARA_R5_UD_CONFIGURATION, socket, timerTrigger); + command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=5,%d,%ld", SARA_R5_UD_CONFIGURATION, socket, timerTrigger); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::socketDirectLinkDataLengthTrigger(int socket, int dataLengthTrigger) { - // valid range is 0, 3-1472 for UDP - if (!((dataLengthTrigger == 0) || ((dataLengthTrigger >= 3) && (dataLengthTrigger <= 1472)))) - return SARA_R5_ERROR_ERROR; + // valid range is 0, 3-1472 for UDP + if (!((dataLengthTrigger == 0) || ((dataLengthTrigger >= 3) && (dataLengthTrigger <= 1472)))) + return SARA_R5_ERROR_ERROR; - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=6,%d,%d", SARA_R5_UD_CONFIGURATION, socket, dataLengthTrigger); + command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=6,%d,%d", SARA_R5_UD_CONFIGURATION, socket, dataLengthTrigger); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::socketDirectLinkCharacterTrigger(int socket, int characterTrigger) { - // The allowed range is -1, 0-255, the factory-programmed value is -1; -1 means trigger disabled. - if (!((characterTrigger >= -1) && (characterTrigger <= 255))) - return SARA_R5_ERROR_ERROR; + // The allowed range is -1, 0-255, the factory-programmed value is -1; -1 means trigger disabled. + if (!((characterTrigger >= -1) && (characterTrigger <= 255))) + return SARA_R5_ERROR_ERROR; - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=7,%d,%d", SARA_R5_UD_CONFIGURATION, socket, characterTrigger); + command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=7,%d,%d", SARA_R5_UD_CONFIGURATION, socket, characterTrigger); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::socketDirectLinkCongestionTimer(int socket, unsigned long congestionTimer) { - // valid range is 0, 1000-72000 - if (!((congestionTimer == 0) || ((congestionTimer >= 1000) && (congestionTimer <= 72000)))) - return SARA_R5_ERROR_ERROR; + // valid range is 0, 1000-72000 + if (!((congestionTimer == 0) || ((congestionTimer >= 1000) && (congestionTimer <= 72000)))) + return SARA_R5_ERROR_ERROR; - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=8,%d,%ld", SARA_R5_UD_CONFIGURATION, socket, congestionTimer); + command = sara_r5_calloc_char(strlen(SARA_R5_UD_CONFIGURATION) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=8,%d,%ld", SARA_R5_UD_CONFIGURATION, socket, congestionTimer); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } //Issues command to get last socket error, then prints to serial. Also updates rx/backlog buffers. int SARA_R5::socketGetLastError() { - SARA_R5_error_t err; - char *command; - char *response; - int errorCode = -1; + SARA_R5_error_t err; + char *command; + char *response; + int errorCode = -1; - command=sara_r5_calloc_char(64); + command = sara_r5_calloc_char(64); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; - response=sara_r5_calloc_char(128); + response = sara_r5_calloc_char(128); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } - sprintf(command, "%s", SARA_R5_GET_ERROR); + sprintf(command, "%s", SARA_R5_GET_ERROR); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + if (err == SARA_R5_ERROR_SUCCESS) { - sscanf(response, "+USOER: %d", &errorCode); - } + sscanf(response, "+USOER: %d", &errorCode); + } - free(command); - free(response); + free(command); + free(response); - return errorCode; + return errorCode; } IPAddress SARA_R5::lastRemoteIP(void) { - return _lastRemoteIP; + return _lastRemoteIP; } SARA_R5_error_t SARA_R5::resetHTTPprofile(int profile) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_HTTP_PROFILE, profile); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_HTTP_PROFILE, profile); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPserverIPaddress(int profile, IPAddress address) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 64); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%d.%d.%d.%d\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_IP, - address[0], address[1], address[2], address[3]); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 64); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%d.%d.%d.%d\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_IP, + address[0], address[1], address[2], address[3]); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPserverName(int profile, String server) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + server.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_NAME, - server.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + server.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_NAME, + server.c_str()); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPusername(int profile, String username) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + username.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_USERNAME, - username.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + username.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_USERNAME, + username.c_str()); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPpassword(int profile, String password) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + password.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_PASSWORD, - password.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 12 + password.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_PASSWORD, + password.c_str()); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPauthentication(int profile, bool authenticate) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_AUTHENTICATION, - authenticate); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_AUTHENTICATION, + authenticate); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPserverPort(int profile, int port) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_PORT, - port); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SERVER_PORT, + port); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setHTTPsecure(int profile, bool secure) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SECURE, - secure); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROFILE) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,%d", SARA_R5_HTTP_PROFILE, profile, SARA_R5_HTTP_OP_CODE_SECURE, + secure); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::ping(String remote_host, int retry, int p_size, - unsigned long timeout, int ttl) + unsigned long timeout, int ttl) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_PING_COMMAND) + 48 + - remote_host.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=\"%s\",%d,%d,%ld,%d", SARA_R5_PING_COMMAND, - remote_host.c_str(), retry, p_size, timeout, ttl); + command = sara_r5_calloc_char(strlen(SARA_R5_PING_COMMAND) + 48 + + remote_host.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=\"%s\",%d,%d,%ld,%d", SARA_R5_PING_COMMAND, + remote_host.c_str(), retry, p_size, timeout, ttl); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::sendHTTPGET(int profile, String path, String responseFilename) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_COMMAND) + 24 + - path.length() + responseFilename.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\",\"%s\"", SARA_R5_HTTP_COMMAND, profile, SARA_R5_HTTP_COMMAND_GET, - path.c_str(), responseFilename.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_COMMAND) + 24 + + path.length() + responseFilename.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\",\"%s\"", SARA_R5_HTTP_COMMAND, profile, SARA_R5_HTTP_COMMAND_GET, + path.c_str(), responseFilename.c_str()); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::sendHTTPPOSTdata(int profile, String path, String responseFilename, - String data, SARA_R5_http_content_types_t httpContentType) + String data, SARA_R5_http_content_types_t httpContentType) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_HTTP_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_HTTP_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_COMMAND) + 24 + - path.length() + responseFilename.length() + data.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\",\"%s\",\"%s\",%d", SARA_R5_HTTP_COMMAND, profile, SARA_R5_HTTP_COMMAND_POST_DATA, - path.c_str(), responseFilename.c_str(), data.c_str(), httpContentType); + command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_COMMAND) + 24 + + path.length() + responseFilename.length() + data.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\",\"%s\",\"%s\",%d", SARA_R5_HTTP_COMMAND, profile, SARA_R5_HTTP_COMMAND_POST_DATA, + path.c_str(), responseFilename.c_str(), data.c_str(), httpContentType); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::getHTTPprotocolError(int profile, int *error_class, int *error_code) @@ -2743,14 +2773,14 @@ SARA_R5_error_t SARA_R5::getHTTPprotocolError(int profile, int *error_class, int command = sara_r5_calloc_char(strlen(SARA_R5_HTTP_PROTOCOL_ERROR) + 4); if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + return SARA_R5_ERROR_OUT_OF_MEMORY; sprintf(command, "%s=%d", SARA_R5_HTTP_PROTOCOL_ERROR, profile); response = sara_r5_calloc_char(48); if (response == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; } err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, @@ -2758,13 +2788,14 @@ SARA_R5_error_t SARA_R5::getHTTPprotocolError(int profile, int *error_class, int if (err == SARA_R5_ERROR_SUCCESS) { - if (sscanf(response, "\r\n+UHTTPER: %d,%d,%d\r\n", - &rprofile, &eclass, &ecode) == 3) - { - *error_class = eclass; - *error_code = ecode; - } - else err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; + if (sscanf(response, "\r\n+UHTTPER: %d,%d,%d\r\n", + &rprofile, &eclass, &ecode) == 3) + { + *error_class = eclass; + *error_code = ecode; + } + else + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } free(command); @@ -2774,186 +2805,186 @@ SARA_R5_error_t SARA_R5::getHTTPprotocolError(int profile, int *error_class, int SARA_R5_error_t SARA_R5::setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, int value) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_PSD_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_PSD_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 24); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,%d", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, - value); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 24); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,%d", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, + value); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, SARA_R5_pdp_protocol_type_t value) { - return (setPDPconfiguration(profile, parameter, (int)value)); + return (setPDPconfiguration(profile, parameter, (int)value)); } SARA_R5_error_t SARA_R5::setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, String value) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_PSD_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_PSD_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 64); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, - value.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 64); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%s\"", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, + value.c_str()); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, IPAddress value) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_PSD_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_PSD_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 64); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d,\"%d.%d.%d.%d\"", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, - value[0], value[1], value[2], value[3]); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONFIG) + 64); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d,\"%d.%d.%d.%d\"", SARA_R5_MESSAGE_PDP_CONFIG, profile, parameter, + value[0], value[1], value[2], value[3]); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::performPDPaction(int profile, SARA_R5_pdp_actions_t action) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (profile >= SARA_R5_NUM_PSD_PROFILES) - return SARA_R5_ERROR_ERROR; + if (profile >= SARA_R5_NUM_PSD_PROFILES) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_ACTION) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d,%d", SARA_R5_MESSAGE_PDP_ACTION, profile, action); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_ACTION) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d,%d", SARA_R5_MESSAGE_PDP_ACTION, profile, action); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::activatePDPcontext(bool status, int cid) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - if (cid >= SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS) - return SARA_R5_ERROR_ERROR; + if (cid >= SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS) + return SARA_R5_ERROR_ERROR; - command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE) + 32); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (cid == -1) - sprintf(command, "%s=%d", SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE, status); - else - sprintf(command, "%s=%d,%d", SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE, status, cid); + command = sara_r5_calloc_char(strlen(SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE) + 32); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (cid == -1) + sprintf(command, "%s=%d", SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE, status); + else + sprintf(command, "%s=%d,%d", SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE, status, cid); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } bool SARA_R5::isGPSon(void) { - SARA_R5_error_t err; - char *command; - char *response; - bool on = false; + SARA_R5_error_t err; + char *command; + char *response; + bool on = false; - command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_POWER) + 2); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_GNSS_POWER); + command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_POWER) + 2); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_GNSS_POWER); - response = sara_r5_calloc_char(24); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(24); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, - SARA_R5_10_SEC_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, + SARA_R5_10_SEC_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + if (err == SARA_R5_ERROR_SUCCESS) + { + // Example response: "+UGPS: 0" for off "+UGPS: 1,0,1" for on + // Search for a ':' followed by a '1' or ' 1' + char *pch1 = strchr(response, ':'); + if (pch1 != NULL) { - // Example response: "+UGPS: 0" for off "+UGPS: 1,0,1" for on - // Search for a ':' followed by a '1' or ' 1' - char * pch1 = strchr(response, ':'); - if (pch1 != NULL) - { - char * pch2 = strchr(response, '1'); - if ((pch2 != NULL) && ((pch2 == pch1 + 1) || (pch2 == pch1 + 2))) - on = true; - } + char *pch2 = strchr(response, '1'); + if ((pch2 != NULL) && ((pch2 == pch1 + 1) || (pch2 == pch1 + 2))) + on = true; } + } - free(command); - free(response); + free(command); + free(response); - return on; + return on; } SARA_R5_error_t SARA_R5::gpsPower(bool enable, gnss_system_t gnss_sys, gnss_aiding_mode_t gnss_aiding) { - SARA_R5_error_t err; - char *command; - bool gpsState; + SARA_R5_error_t err; + char *command; + bool gpsState; - // Don't turn GPS on/off if it's already on/off - gpsState = isGPSon(); - if ((enable && gpsState) || (!enable && !gpsState)) - { - return SARA_R5_ERROR_SUCCESS; - } + // Don't turn GPS on/off if it's already on/off + gpsState = isGPSon(); + if ((enable && gpsState) || (!enable && !gpsState)) + { + return SARA_R5_ERROR_SUCCESS; + } - // GPS power management - command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_POWER) + 32); // gnss_sys could be up to three digits - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (enable) - { - sprintf(command, "%s=1,%d,%d", SARA_R5_GNSS_POWER, gnss_aiding, gnss_sys); - } - else - { - sprintf(command, "%s=0", SARA_R5_GNSS_POWER); - } + // GPS power management + command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_POWER) + 32); // gnss_sys could be up to three digits + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (enable) + { + sprintf(command, "%s=1,%d,%d", SARA_R5_GNSS_POWER, gnss_aiding, gnss_sys); + } + else + { + sprintf(command, "%s=0", SARA_R5_GNSS_POWER); + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, 10000); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, 10000); - free(command); - return err; + free(command); + return err; } /* @@ -3016,70 +3047,70 @@ SARA_R5_error_t SARA_R5::gpsGetSat(uint8_t *sats) SARA_R5_error_t SARA_R5::gpsEnableRmc(bool enable) { - // AT+UGRMC=<0,1> - SARA_R5_error_t err; - char *command; - - // ** Don't call gpsPower here. It causes problems for +UTIME and the PPS signal ** - // ** Call isGPSon and gpsPower externally if required ** - // if (!isGPSon()) - // { - // err = gpsPower(true); - // if (err != SARA_R5_ERROR_SUCCESS) - // { - // return err; - // } - // } + // AT+UGRMC=<0,1> + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_GPRMC) + 3); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_GNSS_GPRMC, enable ? 1 : 0); + // ** Don't call gpsPower here. It causes problems for +UTIME and the PPS signal ** + // ** Call isGPSon and gpsPower externally if required ** + // if (!isGPSon()) + // { + // err = gpsPower(true); + // if (err != SARA_R5_ERROR_SUCCESS) + // { + // return err; + // } + // } + + command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_GPRMC) + 3); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_GNSS_GPRMC, enable ? 1 : 0); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_10_SEC_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_10_SEC_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::gpsGetRmc(struct PositionData *pos, struct SpeedData *spd, - struct ClockData *clk, bool *valid) + struct ClockData *clk, bool *valid) { - SARA_R5_error_t err; - char *command; - char *response; - char *rmcBegin; + SARA_R5_error_t err; + char *command; + char *response; + char *rmcBegin; + + command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_GPRMC) + 2); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_GNSS_GPRMC); - command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_GPRMC) + 2); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_GNSS_GPRMC); + response = sara_r5_calloc_char(96); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - response = sara_r5_calloc_char(96); - if (response == NULL) + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, SARA_R5_10_SEC_TIMEOUT); + if (err == SARA_R5_ERROR_SUCCESS) + { + // Fast-forward response string to $GPRMC starter + rmcBegin = strstr(response, "$GPRMC"); + if (rmcBegin == NULL) { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; + err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; } - - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, response, SARA_R5_10_SEC_TIMEOUT); - if (err == SARA_R5_ERROR_SUCCESS) + else { - // Fast-forward response string to $GPRMC starter - rmcBegin = strstr(response, "$GPRMC"); - if (rmcBegin == NULL) - { - err = SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } - else - { - *valid = parseGPRMCString(rmcBegin, pos, clk, spd); - } + *valid = parseGPRMCString(rmcBegin, pos, clk, spd); } + } - free(command); - free(response); - return err; + free(command); + free(response); + return err; } /* @@ -3099,132 +3130,165 @@ SARA_R5_error_t SARA_R5::gpsGetSpeed(struct SpeedData *speed) */ SARA_R5_error_t SARA_R5::gpsRequest(unsigned int timeout, uint32_t accuracy, - bool detailed, unsigned int sensor) + bool detailed, unsigned int sensor) { - // AT+ULOC=2,,,, - SARA_R5_error_t err; - char *command; + // AT+ULOC=2,,,, + SARA_R5_error_t err; + char *command; - // This function will only work if the GPS module is initially turned off. - if (isGPSon()) - { - gpsPower(false); - } + // This function will only work if the GPS module is initially turned off. + if (isGPSon()) + { + gpsPower(false); + } - if (timeout > 999) - timeout = 999; - if (accuracy > 999999) - accuracy = 999999; + if (timeout > 999) + timeout = 999; + if (accuracy > 999999) + accuracy = 999999; - command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_REQUEST_LOCATION) + 24); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + command = sara_r5_calloc_char(strlen(SARA_R5_GNSS_REQUEST_LOCATION) + 24); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; #if defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_ESP8266) - sprintf(command, "%s=2,%d,%d,%d,%d", SARA_R5_GNSS_REQUEST_LOCATION, - sensor, detailed ? 1 : 0, timeout, accuracy); + sprintf(command, "%s=2,%d,%d,%d,%d", SARA_R5_GNSS_REQUEST_LOCATION, + sensor, detailed ? 1 : 0, timeout, accuracy); #else - sprintf(command, "%s=2,%d,%d,%d,%ld", SARA_R5_GNSS_REQUEST_LOCATION, - sensor, detailed ? 1 : 0, timeout, accuracy); + sprintf(command, "%s=2,%d,%d,%d,%ld", SARA_R5_GNSS_REQUEST_LOCATION, + sensor, detailed ? 1 : 0, timeout, accuracy); #endif - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_10_SEC_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, SARA_R5_10_SEC_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::gpsAidingServerConf(const char *primaryServer, const char *secondaryServer, const char *authToken, - unsigned int days, unsigned int period, unsigned int resolution, - unsigned int gnssTypes, unsigned int mode, unsigned int dataType) + unsigned int days, unsigned int period, unsigned int resolution, + unsigned int gnssTypes, unsigned int mode, unsigned int dataType) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_AIDING_SERVER_CONFIGURATION) + 256); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + command = sara_r5_calloc_char(strlen(SARA_R5_AIDING_SERVER_CONFIGURATION) + 256); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=\"%s\",\"%s\",\"%s\",%d,%d,%d,%d,%d,%d", SARA_R5_AIDING_SERVER_CONFIGURATION, - primaryServer, secondaryServer, authToken, - days, period, resolution, gnssTypes, mode, dataType); + sprintf(command, "%s=\"%s\",\"%s\",\"%s\",%d,%d,%d,%d,%d,%d", SARA_R5_AIDING_SERVER_CONFIGURATION, + primaryServer, secondaryServer, authToken, + days, period, resolution, gnssTypes, mode, dataType); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, - SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); - return err; + free(command); + return err; } SARA_R5_error_t SARA_R5::getFileContents(String filename, String *contents) { - SARA_R5_error_t err; - char *command; - char *response; - char *contentsPtr; + SARA_R5_error_t err; + char *command; + char *response; + char *contentsPtr; - command = sara_r5_calloc_char(strlen(SARA_R5_FILE_SYSTEM_READ_FILE) + 8 + filename.length()); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=\"%s\"", SARA_R5_FILE_SYSTEM_READ_FILE, filename.c_str()); + command = sara_r5_calloc_char(strlen(SARA_R5_FILE_SYSTEM_READ_FILE) + 8 + filename.length()); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=\"%s\"", SARA_R5_FILE_SYSTEM_READ_FILE, filename.c_str()); - response = sara_r5_calloc_char(1072); // Hopefully this should be way more than enough?! (1024 + 48 extra) - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + response = sara_r5_calloc_char(1072); // Hopefully this should be way more than enough?! (1024 + 48 extra) + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return err; - } + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err != SARA_R5_ERROR_SUCCESS) + { + free(command); + free(response); + return err; + } - // Response format: \r\n+URDFILE: "filename",36,"these bytes are the data of the file"\r\n\r\nOK\r\n - contentsPtr = strchr(response, '\"'); // Find the third quote - contentsPtr = strchr(contentsPtr+1, '\"'); - contentsPtr = strchr(contentsPtr+1, '\"'); + // Response format: \r\n+URDFILE: "filename",36,"these bytes are the data of the file"\r\n\r\nOK\r\n + contentsPtr = strchr(response, '\"'); // Find the third quote + contentsPtr = strchr(contentsPtr + 1, '\"'); + contentsPtr = strchr(contentsPtr + 1, '\"'); - if (contentsPtr == NULL) - { - free(command); - free(response); - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } + if (contentsPtr == NULL) + { + free(command); + free(response); + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - bool keepGoing = true; - int bytesRead = 0; + bool keepGoing = true; + int bytesRead = 0; - if (_printDebug == true) _debugPort->print(F("getFileContents: file contents are \"")); + if (_printDebug == true) + _debugPort->print(F("getFileContents: file contents are \"")); - while (keepGoing) + while (keepGoing) + { + char c = *(++contentsPtr); // Increment contentsPtr then copy file char into c + if ((c == '\0') || (c == '\"') || (bytesRead == 1024)) { - char c = *(++contentsPtr); // Increment contentsPtr then copy file char into c - if ((c == '\0') || (c == '\"') || (bytesRead == 1024)) - { - keepGoing = false; - } - else - { - bytesRead++; - contents->concat(c); // Append c to contents - if (_printDebug == true) _debugPort->print(c); - } + keepGoing = false; } - if (_printDebug == true) + else { - _debugPort->println(F("\"")); - _debugPort->print(F("getFileContents: total bytes read: ")); - _debugPort->println(bytesRead); + bytesRead++; + contents->concat(c); // Append c to contents + if (_printDebug == true) + _debugPort->print(c); } + } + if (_printDebug == true) + { + _debugPort->println(F("\"")); + _debugPort->print(F("getFileContents: total bytes read: ")); + _debugPort->println(bytesRead); + } - free(command); - free(response); + free(command); + free(response); - return SARA_R5_ERROR_SUCCESS; + return SARA_R5_ERROR_SUCCESS; +} + +SARA_R5_error_t SARA_R5::modulePowerOff(void) +{ + SARA_R5_error_t err; + char *command; + + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_POWER_OFF) + 6); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + + sprintf(command, "%s", SARA_R5_COMMAND_POWER_OFF); + + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, NULL, + SARA_R5_POWER_OFF_TIMEOUT); + + free(command); + return err; +} + +void SARA_R5::modulePowerOn(void) +{ + if (_powerPin >= 0) + { + powerOn(); + } + else + { + if (_printDebug == true) + _debugPort->println(F("modulePowerOn: not supported. _powerPin not defined.")); + } } ///////////// @@ -3232,69 +3296,77 @@ SARA_R5_error_t SARA_R5::getFileContents(String filename, String *contents) ///////////// SARA_R5_error_t SARA_R5::init(unsigned long baud, - SARA_R5::SARA_R5_init_type_t initType) + SARA_R5::SARA_R5_init_type_t initType) { - SARA_R5_error_t err; + SARA_R5_error_t err; - //If we have recursively called init too many times, bail - _currentInitDepth++; - if (_currentInitDepth == _maxInitDepth) - { - if (_printDebug == true) _debugPort->println(F("Module failed to init. Exiting.")); - return (SARA_R5_ERROR_NO_RESPONSE); - } + //If we have recursively called init too many times, bail + _currentInitDepth++; + if (_currentInitDepth == _maxInitDepth) + { + if (_printDebug == true) + _debugPort->println(F("init: Module failed to init. Exiting.")); + return (SARA_R5_ERROR_NO_RESPONSE); + } - if (_printDebug == true) _debugPort->println(F("Begin module init.")); + if (_printDebug == true) + _debugPort->println(F("init: Begin module init.")); - // There's no 'easy' way to tell if the serial port has already been begun for us. - // We have to assume it has not been begun and so do it here. - // For special cases like Software Serial on ESP32, we need to begin _and_ end the port externally - // _before_ calling the SARA_R5 .begin. - // See SARA-R5_Example2_Identification_ESPSoftwareSerial for more details. - beginSerial(baud); + // There's no 'easy' way to tell if the serial port has already been begun for us. + // We have to assume it has not been begun and so do it here. + // For special cases like Software Serial on ESP32, we need to begin _and_ end the port externally + // _before_ calling the SARA_R5 .begin. + // See SARA-R5_Example2_Identification_ESPSoftwareSerial for more details. + beginSerial(baud); - if (initType == SARA_R5_INIT_AUTOBAUD) + if (initType == SARA_R5_INIT_AUTOBAUD) + { + if (_printDebug == true) + _debugPort->println(F("init: Attempting autobaud connection to module.")); + if (autobaud(baud) != SARA_R5_ERROR_SUCCESS) { - if (_printDebug == true) _debugPort->println(F("Attempting autobaud connection to module.")); - if (autobaud(baud) != SARA_R5_ERROR_SUCCESS) - { - return init(baud, SARA_R5_INIT_RESET); - } + return init(baud, SARA_R5_INIT_RESET); } - else if (initType == SARA_R5_INIT_RESET) + } + else if (initType == SARA_R5_INIT_RESET) + { + if (_printDebug == true) + _debugPort->println(F("init: Power cycling module.")); + powerOff(); + delay(1000); + powerOn(); + delay(2000); + if (at() != SARA_R5_ERROR_SUCCESS) { - if (_printDebug == true) _debugPort->println(F("Power cycling module.")); - powerOn(); - delay(1000); - if (at() != SARA_R5_ERROR_SUCCESS) - { - return init(baud, SARA_R5_INIT_AUTOBAUD); - } + return init(baud, SARA_R5_INIT_AUTOBAUD); } + } - // Use disable echo to test response - err = enableEcho(false); + // Use disable echo to test response + err = enableEcho(false); - if (err != SARA_R5_ERROR_SUCCESS) - { - if (_printDebug == true) _debugPort->println(F("Module failed echo test.")); - return init(baud, SARA_R5_INIT_AUTOBAUD); - } + if (err != SARA_R5_ERROR_SUCCESS) + { + if (_printDebug == true) + _debugPort->println(F("init: Module failed echo test.")); + return init(baud, SARA_R5_INIT_AUTOBAUD); + } - if (_printDebug == true) _debugPort->println(F("Module responded successfully.")); + if (_printDebug == true) + _debugPort->println(F("init: Module responded successfully.")); - _baud = baud; - setGpioMode(GPIO1, NETWORK_STATUS); - //setGpioMode(GPIO2, GNSS_SUPPLY_ENABLE); - setGpioMode(GPIO6, TIME_PULSE_OUTPUT); - setSMSMessageFormat(SARA_R5_MESSAGE_FORMAT_TEXT); - autoTimeZone(true); - for (int i = 0; i < SARA_R5_NUM_SOCKETS; i++) - { - socketClose(i, 100); - } + _baud = baud; + setGpioMode(GPIO1, NETWORK_STATUS); + //setGpioMode(GPIO2, GNSS_SUPPLY_ENABLE); + setGpioMode(GPIO6, TIME_PULSE_OUTPUT); + setSMSMessageFormat(SARA_R5_MESSAGE_FORMAT_TEXT); + autoTimeZone(true); + for (int i = 0; i < SARA_R5_NUM_SOCKETS; i++) + { + socketClose(i, 100); + } - return SARA_R5_ERROR_SUCCESS; + return SARA_R5_ERROR_SUCCESS; } void SARA_R5::invertPowerPin(bool invert) @@ -3302,6 +3374,28 @@ void SARA_R5::invertPowerPin(bool invert) _invertPowerPin = invert; } +// Do a graceful power off. Hold the PWR_ON pin low for SARA_R5_POWER_OFF_PULSE_PERIOD +// Note: +CPWROFF () is preferred to this. +void SARA_R5::powerOff(void) +{ + if (_powerPin >= 0) + { + if (_invertPowerPin) // Set the pin state before making it an output + digitalWrite(_powerPin, HIGH); + else + digitalWrite(_powerPin, LOW); + pinMode(_powerPin, OUTPUT); + if (_invertPowerPin) // Set the pin state + digitalWrite(_powerPin, HIGH); + else + digitalWrite(_powerPin, LOW); + delay(SARA_R5_POWER_OFF_PULSE_PERIOD); + pinMode(_powerPin, INPUT); // Return to high-impedance, rely on (e.g.) SARA module internal pull-up + if (_printDebug == true) + _debugPort->println(F("powerOff: complete")); + } +} + void SARA_R5::powerOn(void) { if (_powerPin >= 0) @@ -3315,116 +3409,154 @@ void SARA_R5::powerOn(void) digitalWrite(_powerPin, HIGH); else digitalWrite(_powerPin, LOW); - delay(SARA_R5_POWER_PULSE_PERIOD); + delay(SARA_R5_POWER_ON_PULSE_PERIOD); pinMode(_powerPin, INPUT); // Return to high-impedance, rely on (e.g.) SARA module internal pull-up - delay(2000); //Wait before sending AT commands to module. 100 is too short. - if (_printDebug == true) _debugPort->println(F("Power cycle complete.")); + //delay(2000); // Do this in init. Wait before sending AT commands to module. 100 is too short. + if (_printDebug == true) + _debugPort->println(F("powerOn: complete")); } } +//This does an abrupt emergency hardware shutdown of the SARA-R5 series modules. +//It only works if you have access to both the RESET_N and PWR_ON pins. +//You cannot use this function on the SparkFun Asset Tracker and RESET_N is tied to the MicroMod processor !RESET!... void SARA_R5::hwReset(void) { - if (_resetPin >= 0) + if ((_resetPin >= 0) && (_powerPin >= 0)) { + digitalWrite(_resetPin, HIGH); // Start by making sure the RESET_N pin is high pinMode(_resetPin, OUTPUT); - digitalWrite(_resetPin, LOW); - delay(SARA_R5_RESET_PULSE_PERIOD); + digitalWrite(_resetPin, HIGH); + + if (_invertPowerPin) // Now pull PWR_ON low - invert as necessary (on the Asset Tracker) + { + digitalWrite(_powerPin, HIGH); // Inverted - Asset Tracker + pinMode(_powerPin, OUTPUT); + digitalWrite(_powerPin, HIGH); + } + else + { + digitalWrite(_powerPin, LOW); // Not inverted + pinMode(_powerPin, OUTPUT); + digitalWrite(_powerPin, LOW); + } + + delay(SARA_R5_RESET_PULSE_PERIOD); // Wait 23 seconds... (Yes, really!) + + digitalWrite(_resetPin, LOW); // Now pull RESET_N low + + delay(100); // Wait a little... (The data sheet doesn't say how long for) + + if (_invertPowerPin) // Now pull PWR_ON high - invert as necessary (on the Asset Tracker) + { + digitalWrite(_powerPin, LOW); // Inverted - Asset Tracker + } + else + { + digitalWrite(_powerPin, HIGH); // Not inverted + } + + delay(1500); // Wait 1.5 seconds + + digitalWrite(_resetPin, HIGH); // Now pull RESET_N high again + pinMode(_resetPin, INPUT); // Return to high-impedance, rely on SARA module internal pull-up + pinMode(_powerPin, INPUT); // Return to high-impedance, rely on SARA module internal pull-up } } SARA_R5_error_t SARA_R5::functionality(SARA_R5_functionality_t function) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_FUNC) + 16); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s=%d", SARA_R5_COMMAND_FUNC, function); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_FUNC) + 16); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s=%d", SARA_R5_COMMAND_FUNC, function); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_3_MIN_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_3_MIN_TIMEOUT); - free(command); + free(command); - return err; + return err; } SARA_R5_error_t SARA_R5::setMNOprofile(mobile_network_operator_t mno, bool autoReset, bool urcNotification) { - SARA_R5_error_t err; - char *command; + SARA_R5_error_t err; + char *command; - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_MNO) + 9); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - if (mno == MNO_SIM_ICCID) // Only add autoReset and urcNotification if mno is MNO_SIM_ICCID - sprintf(command, "%s=%d,%d,%d", SARA_R5_COMMAND_MNO, (uint8_t)mno, (uint8_t) autoReset, (uint8_t) urcNotification); - else - sprintf(command, "%s=%d", SARA_R5_COMMAND_MNO, (uint8_t)mno); + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_MNO) + 9); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + if (mno == MNO_SIM_ICCID) // Only add autoReset and urcNotification if mno is MNO_SIM_ICCID + sprintf(command, "%s=%d,%d,%d", SARA_R5_COMMAND_MNO, (uint8_t)mno, (uint8_t)autoReset, (uint8_t)urcNotification); + else + sprintf(command, "%s=%d", SARA_R5_COMMAND_MNO, (uint8_t)mno); - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + NULL, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - free(command); + free(command); - return err; + return err; } SARA_R5_error_t SARA_R5::getMNOprofile(mobile_network_operator_t *mno) { - SARA_R5_error_t err; - char *command; - char *response; - mobile_network_operator_t o; - int d; - int r; - int u; - int oStore; - - command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_MNO) + 2); - if (command == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; - sprintf(command, "%s?", SARA_R5_COMMAND_MNO); - - response = sara_r5_calloc_char(48); - if (response == NULL) - { - free(command); - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + SARA_R5_error_t err; + char *command; + char *response; + mobile_network_operator_t o; + int d; + int r; + int u; + int oStore; - err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, - response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(command); - free(response); - return err; - } + command = sara_r5_calloc_char(strlen(SARA_R5_COMMAND_MNO) + 2); + if (command == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; + sprintf(command, "%s?", SARA_R5_COMMAND_MNO); + + response = sara_r5_calloc_char(48); + if (response == NULL) + { + free(command); + return SARA_R5_ERROR_OUT_OF_MEMORY; + } + + err = sendCommandWithResponse(command, SARA_R5_RESPONSE_OK, + response, SARA_R5_STANDARD_RESPONSE_TIMEOUT); + if (err != SARA_R5_ERROR_SUCCESS) + { + free(command); + free(response); + return err; + } - int ret = sscanf(response, "\r\n+UMNOPROF: %d,%d,%d,%d", &oStore, &d, &r, &u); - o = (mobile_network_operator_t)oStore; + int ret = sscanf(response, "\r\n+UMNOPROF: %d,%d,%d,%d", &oStore, &d, &r, &u); + o = (mobile_network_operator_t)oStore; - if (ret >= 1) - { - if (_printDebug == true) - { - _debugPort->print("getMNOprofile: MNO is: "); - _debugPort->println(o); - } - *mno = o; - } - else + if (ret >= 1) + { + if (_printDebug == true) { - err = SARA_R5_ERROR_INVALID; + _debugPort->print(F("getMNOprofile: MNO is: ")); + _debugPort->println(o); } + *mno = o; + } + else + { + err = SARA_R5_ERROR_INVALID; + } - free(command); - free(response); + free(command); + free(response); - return err; + return err; } SARA_R5_error_t SARA_R5::waitForResponse(const char *expectedResponse, const char *expectedError, uint16_t timeout) @@ -3433,6 +3565,7 @@ SARA_R5_error_t SARA_R5::waitForResponse(const char *expectedResponse, const cha bool found = false; int responseIndex = 0, errorIndex = 0; int backlogIndex = strlen(saraResponseBacklog); + //bool printedSomething = false; timeIn = millis(); @@ -3441,48 +3574,60 @@ SARA_R5_error_t SARA_R5::waitForResponse(const char *expectedResponse, const cha if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL { char c = readChar(); - if (_printDebug == true) _debugPort->print((String)c); + // if (_printDebug == true) + // { + // if (printedSomething == false) + // _debugPort->print(F("waitForResponse: ")); + // _debugPort->print(c); + // printedSomething = true; + // } if (c == expectedResponse[responseIndex]) { - if (++responseIndex == (int)strlen(expectedResponse)) - { - found = true; - } + if (++responseIndex == (int)strlen(expectedResponse)) + { + found = true; + } } else { - responseIndex = 0; + responseIndex = 0; } - if (c == expectedError[errorIndex]) + if (c == expectedError[errorIndex]) { - if (++errorIndex == (int)strlen(expectedError)) + if (++errorIndex == (int)strlen(expectedError)) { - found = true; - } - } + found = true; + } + } else { - errorIndex = 0; - } - //This is a global array that holds the backlog of any events - //that came in while waiting for response. To be processed later within bufferedPoll(). - saraResponseBacklog[backlogIndex++] = c; + errorIndex = 0; + } + //This is a global array that holds the backlog of any events + //that came in while waiting for response. To be processed later within bufferedPoll(). + //Note: the expectedResponse or expectedError will also be added to the backlog + if (backlogIndex < RXBuffSize) // Don't overflow the buffer + saraResponseBacklog[backlogIndex++] = c; } } - pruneBacklog(); + // if (_printDebug == true) + // if (printedSomething) + // _debugPort->println(); - if (found == true) + pruneBacklog(); // Prune any incoming non-actionable URC's and responses/errors from the backlog + + if (found == true) { - if (errorIndex > 0) + if (responseIndex > 0) // Let success have priority { - return SARA_R5_ERROR_ERROR; - } - else if (responseIndex > 0) + return SARA_R5_ERROR_SUCCESS; + } + else if (errorIndex > 0) { - return SARA_R5_ERROR_SUCCESS; - } - } + return SARA_R5_ERROR_ERROR; + } + } return SARA_R5_ERROR_NO_RESPONSE; } @@ -3495,60 +3640,75 @@ SARA_R5_error_t SARA_R5::sendCommandWithResponse( int index = 0; int destIndex = 0; unsigned int charsRead = 0; + //bool printedSomething = false; - if (_printDebug == true) _debugPort->print("Send Command: "); - if (_printDebug == true) _debugPort->println(String(command)); + // if (_printDebug == true) + // _debugPort->print(F("sendCommandWithResponse: Command: ")); + // if (_printDebug == true) + // _debugPort->println(String(command)); - int backlogIndex = sendCommand(command, at);//Sending command needs to dump data to backlog buffer as well. - unsigned long timeIn = millis(); + int backlogIndex = sendCommand(command, at); //Sending command needs to dump data to backlog buffer as well. + unsigned long timeIn = millis(); - while ((!found) && ((timeIn + commandTimeout) > millis())) + while ((!found) && ((timeIn + commandTimeout) > millis())) { - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL { - char c = readChar(); - if (_printDebug == true) _debugPort->print((String)c); - if (responseDest != NULL) + char c = readChar(); + // if (_printDebug == true) + // { + // if (printedSomething == false) + // _debugPort->print(F("sendCommandWithResponse: Response: ")); + // _debugPort->print(c); + // printedSomething = true; + // } + if (responseDest != NULL) { - responseDest[destIndex++] = c; - } - charsRead++; - if (c == expectedResponse[index]) + responseDest[destIndex++] = c; + } + charsRead++; + if (c == expectedResponse[index]) { - if (++index == (int)strlen(expectedResponse)) + if (++index == (int)strlen(expectedResponse)) { - found = true; - } - } + found = true; + } + } else { - index = 0; - } - //This is a global array that holds the backlog of any events - //that came in while waiting for response. To be processed later within bufferedPoll(). - saraResponseBacklog[backlogIndex++] = c; - } - } + index = 0; + } + //This is a global array that holds the backlog of any events + //that came in while waiting for response. To be processed later within bufferedPoll(). + //Note: the expectedResponse or expectedError will also be added to the backlog + if (backlogIndex < RXBuffSize) // Don't overflow the buffer + saraResponseBacklog[backlogIndex++] = c; + } + } - pruneBacklog(); + // if (_printDebug == true) + // if (printedSomething) + // _debugPort->println(); - if (found) + pruneBacklog(); // Prune any incoming non-actionable URC's and responses/errors from the backlog + + if (found) { - return SARA_R5_ERROR_SUCCESS; + return SARA_R5_ERROR_SUCCESS; } else if (charsRead == 0) { - return SARA_R5_ERROR_NO_RESPONSE; + return SARA_R5_ERROR_NO_RESPONSE; } else { - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; } } // Send a custom command with an expected (potentially partial) response, store entire response SARA_R5_error_t SARA_R5::sendCustomCommandWithResponse(const char *command, const char *expectedResponse, - char *responseDest, unsigned long commandTimeout, bool at) + char *responseDest, unsigned long commandTimeout, bool at) { return sendCommandWithResponse(command, expectedResponse, responseDest, commandTimeout, at); } @@ -3557,555 +3717,596 @@ int SARA_R5::sendCommand(const char *command, bool at) { int backlogIndex = strlen(saraResponseBacklog); + //Spend up to rxWindowUS microseconds copying any incoming serial data into the backlog unsigned long timeIn = micros(); - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL { - while (micros()-timeIn < rxWindowUS && backlogIndex < RXBuffSize) //May need to escape on newline? + while (((micros() - timeIn) < rxWindowUS) && (backlogIndex < RXBuffSize)) //May need to escape on newline? { - if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL + if (hwAvailable() > 0) //hwAvailable can return -1 if the serial port is NULL { - char c = readChar(); - saraResponseBacklog[backlogIndex++] = c; - timeIn = micros(); - } - } - } + char c = readChar(); + saraResponseBacklog[backlogIndex++] = c; + timeIn = micros(); + } + } + } + //Now send the command if (at) - { - hwPrint(SARA_R5_COMMAND_AT); - hwPrint(command); - hwPrint("\r"); - } - else - { - hwPrint(command); - } + { + hwPrint(SARA_R5_COMMAND_AT); + hwPrint(command); + hwPrint("\r"); + } + else + { + hwPrint(command); + } - return backlogIndex; + return backlogIndex; // Return the new backlog length } SARA_R5_error_t SARA_R5::parseSocketReadIndication(int socket, int length) { - SARA_R5_error_t err; - char *readDest; + SARA_R5_error_t err; + char *readDest; - if ((socket < 0) || (length < 0)) - { - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; - } + if ((socket < 0) || (length < 0)) + { + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + } - readDest = sara_r5_calloc_char(length + 1); - if (readDest == NULL) - return SARA_R5_ERROR_OUT_OF_MEMORY; + readDest = sara_r5_calloc_char(length + 1); + if (readDest == NULL) + return SARA_R5_ERROR_OUT_OF_MEMORY; - err = socketRead(socket, length, readDest); - if (err != SARA_R5_ERROR_SUCCESS) - { - free(readDest); - return err; - } + err = socketRead(socket, length, readDest); + if (err != SARA_R5_ERROR_SUCCESS) + { + free(readDest); + return err; + } - if (_socketReadCallback != NULL) - { - _socketReadCallback(socket, String(readDest)); - } + if (_socketReadCallback != NULL) + { + _socketReadCallback(socket, String(readDest)); + } - free(readDest); - return SARA_R5_ERROR_SUCCESS; + free(readDest); + return SARA_R5_ERROR_SUCCESS; } SARA_R5_error_t SARA_R5::parseSocketReadIndicationUDP(int socket, int length) { - SARA_R5_error_t err; - char* readDest; + SARA_R5_error_t err; + char *readDest; - if ((socket < 0) || (length < 0)) + if ((socket < 0) || (length < 0)) { - return SARA_R5_ERROR_UNEXPECTED_RESPONSE; + return SARA_R5_ERROR_UNEXPECTED_RESPONSE; } - readDest = sara_r5_calloc_char(length + 1); - if (readDest == NULL) + readDest = sara_r5_calloc_char(length + 1); + if (readDest == NULL) { - return SARA_R5_ERROR_OUT_OF_MEMORY; - } + return SARA_R5_ERROR_OUT_OF_MEMORY; + } - err = socketReadUDP(socket, length, readDest); - if (err != SARA_R5_ERROR_SUCCESS) + err = socketReadUDP(socket, length, readDest); + if (err != SARA_R5_ERROR_SUCCESS) { free(readDest); - return err; - } + return err; + } - if (_socketReadCallback != NULL) + if (_socketReadCallback != NULL) { - _socketReadCallback(socket, String(readDest)); - } + _socketReadCallback(socket, String(readDest)); + } - free(readDest); - return SARA_R5_ERROR_SUCCESS; + free(readDest); + return SARA_R5_ERROR_SUCCESS; } -SARA_R5_error_t SARA_R5::parseSocketListenIndication(IPAddress localIP, IPAddress remoteIP) +SARA_R5_error_t SARA_R5::parseSocketListenIndication(int listeningSocket, IPAddress localIP, unsigned int listeningPort, int socket, IPAddress remoteIP, unsigned int port) { - _lastLocalIP = localIP; - _lastRemoteIP = remoteIP; - return SARA_R5_ERROR_SUCCESS; + _lastLocalIP = localIP; + _lastRemoteIP = remoteIP; + + if (_socketListenCallback != NULL) + { + _socketListenCallback(listeningSocket, localIP, listeningPort, socket, remoteIP, port); + } + + return SARA_R5_ERROR_SUCCESS; } SARA_R5_error_t SARA_R5::parseSocketCloseIndication(String *closeIndication) { - int search; - int socket; + int search; + int socket; - search = closeIndication->indexOf("UUSOCL: ") + strlen("UUSOCL: "); + search = closeIndication->indexOf("UUSOCL: ") + strlen("UUSOCL: "); - // Socket will be first integer, should be single-digit number between 0-6: - socket = closeIndication->substring(search, search + 1).toInt(); + // Socket will be first integer, should be single-digit number between 0-6: + socket = closeIndication->substring(search, search + 1).toInt(); - if (_socketCloseCallback != NULL) - { - _socketCloseCallback(socket); - } + if (_socketCloseCallback != NULL) + { + _socketCloseCallback(socket); + } - return SARA_R5_ERROR_SUCCESS; + return SARA_R5_ERROR_SUCCESS; } size_t SARA_R5::hwPrint(const char *s) { - if (_hardSerial != NULL) - { - return _hardSerial->print(s); - } + if (_hardSerial != NULL) + { + return _hardSerial->print(s); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->print(s); - } + else if (_softSerial != NULL) + { + return _softSerial->print(s); + } #endif - return (size_t)0; + return (size_t)0; } -size_t SARA_R5::hwWriteData(const char* buff, int len) +size_t SARA_R5::hwWriteData(const char *buff, int len) { - if (_hardSerial != NULL) + if (_hardSerial != NULL) { - return _hardSerial->write((const uint8_t *)buff, len); - } + return _hardSerial->write((const uint8_t *)buff, len); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED else if (_softSerial != NULL) { return _softSerial->write((const uint8_t *)buff, len); } #endif - return (size_t)0; + return (size_t)0; } size_t SARA_R5::hwWrite(const char c) { - if (_hardSerial != NULL) - { - return _hardSerial->write(c); - } + if (_hardSerial != NULL) + { + return _hardSerial->write(c); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->write(c); - } + else if (_softSerial != NULL) + { + return _softSerial->write(c); + } #endif - return (size_t)0; + return (size_t)0; } int SARA_R5::readAvailable(char *inString) { - int len = 0; + int len = 0; - if (_hardSerial != NULL) + if (_hardSerial != NULL) + { + while (_hardSerial->available()) { - while (_hardSerial->available()) - { - char c = (char)_hardSerial->read(); - if (inString != NULL) - { - inString[len++] = c; - } - } - if (inString != NULL) - { - inString[len] = 0; - } - if (_printDebug == true) _debugPort->println(inString); + char c = (char)_hardSerial->read(); + if (inString != NULL) + { + inString[len++] = c; + } + } + if (inString != NULL) + { + inString[len] = 0; } + //if (_printDebug == true) + // _debugPort->println(inString); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) + else if (_softSerial != NULL) + { + while (_softSerial->available()) { - while (_softSerial->available()) - { - char c = (char)_softSerial->read(); - if (inString != NULL) - { - inString[len++] = c; - } - } - if (inString != NULL) - { - inString[len] = 0; - } + char c = (char)_softSerial->read(); + if (inString != NULL) + { + inString[len++] = c; + } + } + if (inString != NULL) + { + inString[len] = 0; } + } #endif - return len; + return len; } char SARA_R5::readChar(void) { - char ret = 0; + char ret = 0; - if (_hardSerial != NULL) - { - ret = (char)_hardSerial->read(); - } + if (_hardSerial != NULL) + { + ret = (char)_hardSerial->read(); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - ret = (char)_softSerial->read(); - } + else if (_softSerial != NULL) + { + ret = (char)_softSerial->read(); + } #endif - return ret; + return ret; } int SARA_R5::hwAvailable(void) { - if (_hardSerial != NULL) - { - return _hardSerial->available(); - } + if (_hardSerial != NULL) + { + return _hardSerial->available(); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - return _softSerial->available(); - } + else if (_softSerial != NULL) + { + return _softSerial->available(); + } #endif - return -1; + return -1; } void SARA_R5::beginSerial(unsigned long baud) { - if (_hardSerial != NULL) - { - _hardSerial->begin(baud); - } + if (_hardSerial != NULL) + { + _hardSerial->begin(baud); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - _softSerial->end(); - _softSerial->begin(baud); - } + else if (_softSerial != NULL) + { + _softSerial->end(); + _softSerial->begin(baud); + } #endif - delay(100); + delay(100); } void SARA_R5::setTimeout(unsigned long timeout) { - if (_hardSerial != NULL) - { - _hardSerial->setTimeout(timeout); - } + if (_hardSerial != NULL) + { + _hardSerial->setTimeout(timeout); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - _softSerial->setTimeout(timeout); - } + else if (_softSerial != NULL) + { + _softSerial->setTimeout(timeout); + } #endif } bool SARA_R5::find(char *target) { - bool found = false; - if (_hardSerial != NULL) - { - found = _hardSerial->find(target); - } + bool found = false; + if (_hardSerial != NULL) + { + found = _hardSerial->find(target); + } #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - else if (_softSerial != NULL) - { - found = _softSerial->find(target); - } + else if (_softSerial != NULL) + { + found = _softSerial->find(target); + } #endif - return found; + return found; } SARA_R5_error_t SARA_R5::autobaud(unsigned long desiredBaud) { - SARA_R5_error_t err = SARA_R5_ERROR_INVALID; - int b = 0; + SARA_R5_error_t err = SARA_R5_ERROR_INVALID; + int b = 0; - while ((err != SARA_R5_ERROR_SUCCESS) && (b < NUM_SUPPORTED_BAUD)) - { - beginSerial(SARA_R5_SUPPORTED_BAUD[b++]); - setBaud(desiredBaud); - delay(200); - beginSerial(desiredBaud); - err = at(); - } - if (err == SARA_R5_ERROR_SUCCESS) - { - beginSerial(desiredBaud); - } - return err; + while ((err != SARA_R5_ERROR_SUCCESS) && (b < NUM_SUPPORTED_BAUD)) + { + beginSerial(SARA_R5_SUPPORTED_BAUD[b++]); + setBaud(desiredBaud); + delay(200); + beginSerial(desiredBaud); + err = at(); + } + if (err == SARA_R5_ERROR_SUCCESS) + { + beginSerial(desiredBaud); + } + return err; } char *SARA_R5::sara_r5_calloc_char(size_t num) { - return (char *)calloc(num, sizeof(char)); + return (char *)calloc(num, sizeof(char)); } //This prunes the backlog of non-actionable events. If new actionable events are added, you must modify the if statement. void SARA_R5::pruneBacklog() { - char* event; - char pruneBuffer[RXBuffSize]; - memset(pruneBuffer, 0, RXBuffSize); - - event = strtok(saraResponseBacklog, "\r\n"); - while (event != NULL) //If event actionable, add to pruneBuffer. + char *event; + char pruneBuffer[RXBuffSize]; + memset(pruneBuffer, 0, RXBuffSize); // Create a buffer to store the stuff we don't want to prune + + // if (strlen(saraResponseBacklog) > 0) //Handy for debugging new parsing. + // { + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: pruned backlog was:")); + // if (_printDebug == true) + // _debugPort->println(saraResponseBacklog); + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: end of pruned backlog")); + // } + // else + // { + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: backlog was empty")); + // } + + event = strtok(saraResponseBacklog, "\r\n"); // Look for an 'event' - something ending in \r\n + + while (event != NULL) //If event actionable, add to pruneBuffer. { - if (strstr(event, "+UUSORD:") != NULL - || strstr(event, "+UUSOLI:") != NULL - || strstr(event, "+UUSOCL:") != NULL - || strstr(event, "+UUSORF:") != NULL) - { - strcat(pruneBuffer, event); - strcat(pruneBuffer, "\r\n"); //strtok blows away delimiter, but we want that for later. - } - event = strtok(NULL, "\r\n"); - } - memset(saraResponseBacklog, 0, RXBuffSize);//Clear out backlog buffer. - strcpy(saraResponseBacklog, pruneBuffer); + // These are the events we want to keep so they can be processed by poll / bufferedPoll + if ((strstr(event, "+UUSORD:") != NULL) + || (strstr(event, "+UUSORF:") != NULL) + || (strstr(event, "+UUSOLI:") != NULL) + || (strstr(event, "+UUSOCL:") != NULL) + || (strstr(event, "+UULOC:") != NULL) + || (strstr(event, "+UUSIMSTAT:") != NULL) + || (strstr(event, "+UUPSDA:") != NULL) + || (strstr(event, "+UUPING:") != NULL) + || (strstr(event, "+UUHTTPCR:") != NULL)) + { + strcat(pruneBuffer, event); + strcat(pruneBuffer, "\r\n"); //strtok blows away delimiter, but we want that for later. + } + + event = strtok(NULL, "\r\n"); // Walk though any remaining events + } - if (strlen(saraResponseBacklog) > 0) //Handy for debugging new parsing. - { - if (_printDebug == true) _debugPort->println("PRUNING SAVED: "); - if (_printDebug == true) _debugPort->println(saraResponseBacklog); - if (_printDebug == true) _debugPort->println("fin."); - } + memset(saraResponseBacklog, 0, RXBuffSize); //Clear out backlog buffer. + strcpy(saraResponseBacklog, pruneBuffer); //Copy the stuff we didn't prune into the backlog + + // if (strlen(saraResponseBacklog) > 0) //Handy for debugging new parsing. + // { + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: pruned backlog is now:")); + // if (_printDebug == true) + // _debugPort->println(saraResponseBacklog); + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: end of pruned backlog")); + // } + // else + // { + // if (_printDebug == true) + // _debugPort->println(F("pruneBacklog: backlog is now empty")); + // } - free(event); + free(event); } // GPS Helper Functions: // Read a source string until a delimiter is hit, store the result in destination char *SARA_R5::readDataUntil(char *destination, unsigned int destSize, - char *source, char delimiter) + char *source, char delimiter) { - char *strEnd; - size_t len; + char *strEnd; + size_t len; - strEnd = strchr(source, delimiter); + strEnd = strchr(source, delimiter); - if (strEnd != NULL) - { - len = strEnd - source; - memset(destination, 0, destSize); - memcpy(destination, source, len); - } + if (strEnd != NULL) + { + len = strEnd - source; + memset(destination, 0, destSize); + memcpy(destination, source, len); + } - return strEnd; + return strEnd; } bool SARA_R5::parseGPRMCString(char *rmcString, PositionData *pos, - ClockData *clk, SpeedData *spd) -{ - char *ptr, *search; - unsigned long tTemp; - char tempData[TEMP_NMEA_DATA_SIZE]; - - // if (_printDebug == true) - // { - // _debugPort->println(F("parseGPRMCString: rmcString: ")); - // _debugPort->println(rmcString); - // } - - // Fast-forward test to first value: - ptr = strchr(rmcString, ','); - ptr++; // Move ptr past first comma - - // If the next character is another comma, there's no time data - // Find time: - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - // Next comma should be present and not the next position - if ((search != NULL) && (search != ptr)) - { - pos->utc = atof(tempData); // Extract hhmmss.ss as float - tTemp = pos->utc; // Convert to unsigned long (discard the digits beyond the decimal point) - clk->time.ms = ((unsigned int)(pos->utc * 100)) % 100; // Extract the milliseconds - clk->time.hour = tTemp / 10000; - tTemp -= ((unsigned long)clk->time.hour * 10000); - clk->time.minute = tTemp / 100; - tTemp -= ((unsigned long)clk->time.minute * 100); - clk->time.second = tTemp; - } - else - { - pos->utc = 0.0; - clk->time.hour = 0; - clk->time.minute = 0; - clk->time.second = 0; - } - ptr = search + 1; // Move pointer to next value + ClockData *clk, SpeedData *spd) +{ + char *ptr, *search; + unsigned long tTemp; + char tempData[TEMP_NMEA_DATA_SIZE]; + + // if (_printDebug == true) + // { + // _debugPort->println(F("parseGPRMCString: rmcString: ")); + // _debugPort->println(rmcString); + // } + + // Fast-forward test to first value: + ptr = strchr(rmcString, ','); + ptr++; // Move ptr past first comma + + // If the next character is another comma, there's no time data + // Find time: + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + // Next comma should be present and not the next position + if ((search != NULL) && (search != ptr)) + { + pos->utc = atof(tempData); // Extract hhmmss.ss as float + tTemp = pos->utc; // Convert to unsigned long (discard the digits beyond the decimal point) + clk->time.ms = ((unsigned int)(pos->utc * 100)) % 100; // Extract the milliseconds + clk->time.hour = tTemp / 10000; + tTemp -= ((unsigned long)clk->time.hour * 10000); + clk->time.minute = tTemp / 100; + tTemp -= ((unsigned long)clk->time.minute * 100); + clk->time.second = tTemp; + } + else + { + pos->utc = 0.0; + clk->time.hour = 0; + clk->time.minute = 0; + clk->time.second = 0; + } + ptr = search + 1; // Move pointer to next value - // Find status character: - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - // Should be a single character: V = Data invalid, A = Data valid - if ((search != NULL) && (search == ptr + 1)) - { - pos->status = *ptr; // Assign char at ptr to status - } - else - { - pos->status = 'X'; // Made up very bad status - } - ptr = search + 1; + // Find status character: + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + // Should be a single character: V = Data invalid, A = Data valid + if ((search != NULL) && (search == ptr + 1)) + { + pos->status = *ptr; // Assign char at ptr to status + } + else + { + pos->status = 'X'; // Made up very bad status + } + ptr = search + 1; - // Find latitude: - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - pos->lat = atof(tempData); // Extract ddmm.mmmmm as float - unsigned long lat_deg = pos->lat / 100; // Extract the degrees - pos->lat -= (float)lat_deg * 100.0; // Subtract the degrees leaving only the minutes - pos->lat /= 60.0; // Convert minutes into degrees - pos->lat += (float)lat_deg; // Finally add the degrees back on again - } - else - { - pos->lat = 0.0; - } - ptr = search + 1; + // Find latitude: + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + pos->lat = atof(tempData); // Extract ddmm.mmmmm as float + unsigned long lat_deg = pos->lat / 100; // Extract the degrees + pos->lat -= (float)lat_deg * 100.0; // Subtract the degrees leaving only the minutes + pos->lat /= 60.0; // Convert minutes into degrees + pos->lat += (float)lat_deg; // Finally add the degrees back on again + } + else + { + pos->lat = 0.0; + } + ptr = search + 1; - // Find latitude hemishpere - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search == ptr + 1)) - { - if (*ptr == 'S') // Is the latitude South - pos->lat *= -1.0; // Make lat negative - } - ptr = search + 1; + // Find latitude hemishpere + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search == ptr + 1)) + { + if (*ptr == 'S') // Is the latitude South + pos->lat *= -1.0; // Make lat negative + } + ptr = search + 1; - // Find longitude: - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - pos->lon = atof(tempData); // Extract dddmm.mmmmm as float - unsigned long lon_deg = pos->lon / 100; // Extract the degrees - pos->lon -= (float)lon_deg * 100.0; // Subtract the degrees leaving only the minutes - pos->lon /= 60.0; // Convert minutes into degrees - pos->lon += (float)lon_deg; // Finally add the degrees back on again - } - else - { - pos->lon = 0.0; - } - ptr = search + 1; + // Find longitude: + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + pos->lon = atof(tempData); // Extract dddmm.mmmmm as float + unsigned long lon_deg = pos->lon / 100; // Extract the degrees + pos->lon -= (float)lon_deg * 100.0; // Subtract the degrees leaving only the minutes + pos->lon /= 60.0; // Convert minutes into degrees + pos->lon += (float)lon_deg; // Finally add the degrees back on again + } + else + { + pos->lon = 0.0; + } + ptr = search + 1; - // Find longitude hemishpere - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search == ptr + 1)) - { - if (*ptr == 'W') // Is the longitude West - pos->lon *= -1.0; // Make lon negative - } - ptr = search + 1; + // Find longitude hemishpere + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search == ptr + 1)) + { + if (*ptr == 'W') // Is the longitude West + pos->lon *= -1.0; // Make lon negative + } + ptr = search + 1; - // Find speed - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - spd->speed = atof(tempData); // Extract speed over ground in knots - spd->speed *= 0.514444; // Convert to m/s - } - else - { - spd->speed = 0.0; - } - ptr = search + 1; + // Find speed + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + spd->speed = atof(tempData); // Extract speed over ground in knots + spd->speed *= 0.514444; // Convert to m/s + } + else + { + spd->speed = 0.0; + } + ptr = search + 1; - // Find course over ground - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - spd->cog = atof(tempData); - } - else - { - spd->cog = 0.0; - } - ptr = search + 1; + // Find course over ground + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + spd->cog = atof(tempData); + } + else + { + spd->cog = 0.0; + } + ptr = search + 1; - // Find date - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - tTemp = atol(tempData); - clk->date.day = tTemp / 10000; - tTemp -= ((unsigned long)clk->date.day * 10000); - clk->date.month = tTemp / 100; - tTemp -= ((unsigned long)clk->date.month * 100); - clk->date.year = tTemp; - } - else - { - clk->date.day = 0; - clk->date.month = 0; - clk->date.year = 0; - } - ptr = search + 1; + // Find date + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + tTemp = atol(tempData); + clk->date.day = tTemp / 10000; + tTemp -= ((unsigned long)clk->date.day * 10000); + clk->date.month = tTemp / 100; + tTemp -= ((unsigned long)clk->date.month * 100); + clk->date.year = tTemp; + } + else + { + clk->date.day = 0; + clk->date.month = 0; + clk->date.year = 0; + } + ptr = search + 1; - // Find magnetic variation in degrees: - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search != ptr)) - { - spd->magVar = atof(tempData); - } - else - { - spd->magVar = 0.0; - } - ptr = search + 1; + // Find magnetic variation in degrees: + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search != ptr)) + { + spd->magVar = atof(tempData); + } + else + { + spd->magVar = 0.0; + } + ptr = search + 1; - // Find magnetic variation direction - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); - if ((search != NULL) && (search == ptr + 1)) - { - if (*ptr == 'W') // Is the magnetic variation West - spd->magVar *= -1.0; // Make magnetic variation negative - } - ptr = search + 1; + // Find magnetic variation direction + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, ','); + if ((search != NULL) && (search == ptr + 1)) + { + if (*ptr == 'W') // Is the magnetic variation West + spd->magVar *= -1.0; // Make magnetic variation negative + } + ptr = search + 1; - // Find position system mode - // Possible values for posMode: N = No fix, E = Estimated/Dead reckoning fix, A = Autonomous GNSS fix, - // D = Differential GNSS fix, F = RTK float, R = RTK fixed - search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, '*'); - if ((search != NULL) && (search = ptr + 1)) - { - pos->mode = *ptr; - } - else - { - pos->mode = 'X'; - } - ptr = search + 1; + // Find position system mode + // Possible values for posMode: N = No fix, E = Estimated/Dead reckoning fix, A = Autonomous GNSS fix, + // D = Differential GNSS fix, F = RTK float, R = RTK fixed + search = readDataUntil(tempData, TEMP_NMEA_DATA_SIZE, ptr, '*'); + if ((search != NULL) && (search = ptr + 1)) + { + pos->mode = *ptr; + } + else + { + pos->mode = 'X'; + } + ptr = search + 1; - if (pos->status == 'A') - { - return true; - } - return false; + if (pos->status == 'A') + { + return true; + } + return false; } diff --git a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h index 1605547..89d84cb 100644 --- a/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h +++ b/src/SparkFun_u-blox_SARA-R5_Arduino_Library.h @@ -23,43 +23,43 @@ #include "WProgram.h" #endif -#ifdef ARDUINO_ARCH_AVR // Arduino AVR boards (Uno, Pro Micro, etc.) +#ifdef ARDUINO_ARCH_AVR // Arduino AVR boards (Uno, Pro Micro, etc.) #define SARA_R5_SOFTWARE_SERIAL_ENABLED // Enable software serial #endif -#ifdef ARDUINO_ARCH_SAMD // Arduino SAMD boards (SAMD21, etc.) +#ifdef ARDUINO_ARCH_SAMD // Arduino SAMD boards (SAMD21, etc.) #define SARA_R5_SOFTWARE_SERIAL_ENABLEDx // Disable software serial #endif -#ifdef ARDUINO_ARCH_APOLLO3 // Arduino Apollo boards (Artemis module, RedBoard Artemis, etc) +#ifdef ARDUINO_ARCH_APOLLO3 // Arduino Apollo boards (Artemis module, RedBoard Artemis, etc) #define SARA_R5_SOFTWARE_SERIAL_ENABLEDx // Disable software serial (no longer supported with v2 of Apollo3) // Note: paulvha has provided software serial support for v2 of the Apollo3 / Artemis core. // Further details are available at: // https://github.com/paulvha/apollo3/tree/master/SoftwareSerial #endif -#ifdef ARDUINO_ARCH_STM32 // STM32 based boards (Disco, Nucleo, etc) +#ifdef ARDUINO_ARCH_STM32 // STM32 based boards (Disco, Nucleo, etc) #define SARA_R5_SOFTWARE_SERIAL_ENABLED // Enable software serial #endif -#ifdef ARDUINO_ARCH_ESP32 // ESP32 based boards +#ifdef ARDUINO_ARCH_ESP32 // ESP32 based boards // Check to see if ESP Software Serial has been included // Note: you need to #include at the very start of your script, // _before_ the #include , for this to work. // See SARA-R5_Example2_Identification_ESPSoftwareSerial for more details. -#if __has_include( ) +#if __has_include( ) #define SARA_R5_SOFTWARE_SERIAL_ENABLED // Enable software serial #else #define SARA_R5_SOFTWARE_SERIAL_ENABLEDx // Disable software serial #endif #endif -#ifdef ARDUINO_ARCH_ESP8266 // ESP8266 based boards +#ifdef ARDUINO_ARCH_ESP8266 // ESP8266 based boards // Check to see if ESP Software Serial has been included // Note: you need to #include at the very start of your script, // _before_ the #include , for this to work. // See SARA-R5_Example2_Identification_ESPSoftwareSerial for more details. -#if __has_include( ) +#if __has_include( ) #define SARA_R5_SOFTWARE_SERIAL_ENABLED // Enable software serial #else #define SARA_R5_SOFTWARE_SERIAL_ENABLEDx // Disable software serial @@ -81,30 +81,32 @@ #define SARA_R5_2_MIN_TIMEOUT 120000 #define SARA_R5_3_MIN_TIMEOUT 180000 #define SARA_R5_SET_BAUD_TIMEOUT 500 -#define SARA_R5_POWER_PULSE_PERIOD 3200 -#define SARA_R5_RESET_PULSE_PERIOD 10000 +#define SARA_R5_POWER_OFF_PULSE_PERIOD 3200 // Hold PWR_ON low for this long to power the module off +#define SARA_R5_POWER_ON_PULSE_PERIOD 100 // Hold PWR_ON low for this long to power the module on (SARA-R510M8S) +#define SARA_R5_RESET_PULSE_PERIOD 23000 // Used to perform an abrupt emergency hardware shutdown. 23 seconds... (Yes, really!) +#define SARA_R5_POWER_OFF_TIMEOUT 40000 // Datasheet says 40 seconds... #define SARA_R5_IP_CONNECT_TIMEOUT 130000 #define SARA_R5_POLL_DELAY 1 #define SARA_R5_SOCKET_WRITE_TIMEOUT 10000 // ## Suported AT Commands // ### General -const char SARA_R5_COMMAND_AT[] = "AT"; // AT "Test" -const char SARA_R5_COMMAND_ECHO[] = "E"; // Local Echo -const char SARA_R5_COMMAND_MANU_ID[] = "+CGMI"; // Manufacturer identification -const char SARA_R5_COMMAND_MODEL_ID[] = "+CGMM"; // Model identification +const char SARA_R5_COMMAND_AT[] = "AT"; // AT "Test" +const char SARA_R5_COMMAND_ECHO[] = "E"; // Local Echo +const char SARA_R5_COMMAND_MANU_ID[] = "+CGMI"; // Manufacturer identification +const char SARA_R5_COMMAND_MODEL_ID[] = "+CGMM"; // Model identification const char SARA_R5_COMMAND_FW_VER_ID[] = "+CGMR"; // Firmware version identification const char SARA_R5_COMMAND_SERIAL_NO[] = "+CGSN"; // Product serial number -const char SARA_R5_COMMAND_IMEI[] = "+CSN"; // IMEI identification -const char SARA_R5_COMMAND_IMSI[] = "+CIMI"; // IMSI identification -const char SARA_R5_COMMAND_CCID[] = "+CCID"; // SIM CCID -const char SARA_R5_COMMAND_REQ_CAP[] = "+GCAP"; // Request capabilities list +const char SARA_R5_COMMAND_IMEI[] = "+CSN"; // IMEI identification +const char SARA_R5_COMMAND_IMSI[] = "+CIMI"; // IMSI identification +const char SARA_R5_COMMAND_CCID[] = "+CCID"; // SIM CCID +const char SARA_R5_COMMAND_REQ_CAP[] = "+GCAP"; // Request capabilities list // ### Control and status const char SARA_R5_COMMAND_POWER_OFF[] = "+CPWROFF"; // Module switch off -const char SARA_R5_COMMAND_FUNC[] = "+CFUN"; // Functionality (reset, etc.) -const char SARA_R5_COMMAND_CLOCK[] = "+CCLK"; // Real-time clock -const char SARA_R5_COMMAND_AUTO_TZ[] = "+CTZU"; // Automatic time zone update -const char SARA_R5_COMMAND_TZ_REPORT[] = "+CTZR"; // Time zone reporting +const char SARA_R5_COMMAND_FUNC[] = "+CFUN"; // Functionality (reset, etc.) +const char SARA_R5_COMMAND_CLOCK[] = "+CCLK"; // Real-time clock +const char SARA_R5_COMMAND_AUTO_TZ[] = "+CTZU"; // Automatic time zone update +const char SARA_R5_COMMAND_TZ_REPORT[] = "+CTZR"; // Time zone reporting // ### Network service const char SARA_R5_COMMAND_CNUM[] = "+CNUM"; // Subscriber number const char SARA_R5_SIGNAL_QUALITY[] = "+CSQ"; @@ -115,50 +117,50 @@ const char SARA_R5_COMMAND_MNO[] = "+UMNOPROF"; // MNO (mobile network operator) // ### SIM const char SARA_R5_SIM_STATE[] = "+USIMSTAT"; // ### SMS -const char SARA_R5_MESSAGE_FORMAT[] = "+CMGF"; // Set SMS message format -const char SARA_R5_SEND_TEXT[] = "+CMGS"; // Send SMS message -const char SARA_R5_NEW_MESSAGE_IND[] = "+CNMI"; // New [SMS] message indication +const char SARA_R5_MESSAGE_FORMAT[] = "+CMGF"; // Set SMS message format +const char SARA_R5_SEND_TEXT[] = "+CMGS"; // Send SMS message +const char SARA_R5_NEW_MESSAGE_IND[] = "+CNMI"; // New [SMS] message indication const char SARA_R5_PREF_MESSAGE_STORE[] = "+CPMS"; // Preferred message storage -const char SARA_R5_READ_TEXT_MESSAGE[] = "+CMGR"; // Read message +const char SARA_R5_READ_TEXT_MESSAGE[] = "+CMGR"; // Read message // V24 control and V25ter (UART interface) -const char SARA_R5_FLOW_CONTROL[] = "&K"; // Flow control +const char SARA_R5_FLOW_CONTROL[] = "&K"; // Flow control const char SARA_R5_COMMAND_BAUD[] = "+IPR"; // Baud rate // ### Packet switched data services -const char SARA_R5_MESSAGE_PDP_DEF[] = "+CGDCONT"; // Packet switched Data Profile context definition -const char SARA_R5_MESSAGE_PDP_CONFIG[] = "+UPSD"; // Packet switched Data Profile configuration -const char SARA_R5_MESSAGE_PDP_ACTION[] = "+UPSDA"; // Perform the action for the specified PSD profile +const char SARA_R5_MESSAGE_PDP_DEF[] = "+CGDCONT"; // Packet switched Data Profile context definition +const char SARA_R5_MESSAGE_PDP_CONFIG[] = "+UPSD"; // Packet switched Data Profile configuration +const char SARA_R5_MESSAGE_PDP_ACTION[] = "+UPSDA"; // Perform the action for the specified PSD profile const char SARA_R5_MESSAGE_PDP_CONTEXT_ACTIVATE[] = "+CGACT"; // Activates or deactivates the specified PDP context const char SARA_R5_MESSAGE_ENTER_PPP[] = "D"; // ### GPIO const char SARA_R5_COMMAND_GPIO[] = "+UGPIOC"; // GPIO Configuration // ### IP -const char SARA_R5_CREATE_SOCKET[] = "+USOCR"; // Create a new socket -const char SARA_R5_CLOSE_SOCKET[] = "+USOCL"; // Close a socket -const char SARA_R5_CONNECT_SOCKET[] = "+USOCO"; // Connect to server on socket -const char SARA_R5_WRITE_SOCKET[] = "+USOWR"; // Write data to a socket -const char SARA_R5_WRITE_UDP_SOCKET[] = "+USOST"; // Write data to a UDP socket -const char SARA_R5_READ_SOCKET[] = "+USORD"; // Read from a socket -const char SARA_R5_READ_UDP_SOCKET[] = "+USORF"; // Read UDP data from a socket -const char SARA_R5_LISTEN_SOCKET[] = "+USOLI"; // Listen for connection on socket -const char SARA_R5_GET_ERROR[] = "+USOER"; // Get last socket error. +const char SARA_R5_CREATE_SOCKET[] = "+USOCR"; // Create a new socket +const char SARA_R5_CLOSE_SOCKET[] = "+USOCL"; // Close a socket +const char SARA_R5_CONNECT_SOCKET[] = "+USOCO"; // Connect to server on socket +const char SARA_R5_WRITE_SOCKET[] = "+USOWR"; // Write data to a socket +const char SARA_R5_WRITE_UDP_SOCKET[] = "+USOST"; // Write data to a UDP socket +const char SARA_R5_READ_SOCKET[] = "+USORD"; // Read from a socket +const char SARA_R5_READ_UDP_SOCKET[] = "+USORF"; // Read UDP data from a socket +const char SARA_R5_LISTEN_SOCKET[] = "+USOLI"; // Listen for connection on socket +const char SARA_R5_GET_ERROR[] = "+USOER"; // Get last socket error. const char SARA_R5_SOCKET_DIRECT_LINK[] = "+USODL"; // Set socket in Direct Link mode -const char SARA_R5_UD_CONFIGURATION[] = "+UDCONF"; // User Datagram Configuration +const char SARA_R5_UD_CONFIGURATION[] = "+UDCONF"; // User Datagram Configuration // ### Ping const char SARA_R5_PING_COMMAND[] = "+UPING"; // Ping // ### HTTP -const char SARA_R5_HTTP_PROFILE[] = "+UHTTP"; // Configure the HTTP profile. Up to 4 different profiles can be defined -const char SARA_R5_HTTP_COMMAND[] = "+UHTTPC"; // Trigger the specified HTTP command +const char SARA_R5_HTTP_PROFILE[] = "+UHTTP"; // Configure the HTTP profile. Up to 4 different profiles can be defined +const char SARA_R5_HTTP_COMMAND[] = "+UHTTPC"; // Trigger the specified HTTP command const char SARA_R5_HTTP_PROTOCOL_ERROR[] = "+UHTTPER"; // Retrieves the error class and code of the latest HTTP operation on the specified HTTP profile. // ### GNSS -const char SARA_R5_GNSS_POWER[] = "+UGPS"; // GNSS power management configuration -const char SARA_R5_GNSS_ASSISTED_IND[] = "+UGIND"; // Assisted GNSS unsolicited indication -const char SARA_R5_GNSS_REQUEST_LOCATION[] = "+ULOC"; // Ask for localization information -const char SARA_R5_GNSS_GPRMC[] = "+UGRMC"; // Ask for localization information -const char SARA_R5_GNSS_REQUEST_TIME[] = "+UTIME"; // Ask for time information from cellular modem (CellTime) -const char SARA_R5_GNSS_TIME_INDICATION[] = "+UTIMEIND"; // Time information request status unsolicited indication -const char SARA_R5_GNSS_TIME_CONFIGURATION[] = "+UTIMECFG"; // Sets time configuration -const char SARA_R5_GNSS_CONFIGURE_SENSOR[] = "+ULOCGNSS"; // Configure GNSS sensor -const char SARA_R5_GNSS_CONFIGURE_LOCATION[] = "+ULOCCELL"; // Configure cellular location sensor (CellLocate®) +const char SARA_R5_GNSS_POWER[] = "+UGPS"; // GNSS power management configuration +const char SARA_R5_GNSS_ASSISTED_IND[] = "+UGIND"; // Assisted GNSS unsolicited indication +const char SARA_R5_GNSS_REQUEST_LOCATION[] = "+ULOC"; // Ask for localization information +const char SARA_R5_GNSS_GPRMC[] = "+UGRMC"; // Ask for localization information +const char SARA_R5_GNSS_REQUEST_TIME[] = "+UTIME"; // Ask for time information from cellular modem (CellTime) +const char SARA_R5_GNSS_TIME_INDICATION[] = "+UTIMEIND"; // Time information request status unsolicited indication +const char SARA_R5_GNSS_TIME_CONFIGURATION[] = "+UTIMECFG"; // Sets time configuration +const char SARA_R5_GNSS_CONFIGURE_SENSOR[] = "+ULOCGNSS"; // Configure GNSS sensor +const char SARA_R5_GNSS_CONFIGURE_LOCATION[] = "+ULOCCELL"; // Configure cellular location sensor (CellLocate®) const char SARA_R5_AIDING_SERVER_CONFIGURATION[] = "+UGSRV"; // Configure aiding server (CellLocate®) // ### File System const char SARA_R5_FILE_SYSTEM_READ_FILE[] = "+URDFILE"; // Read a file @@ -204,220 +206,220 @@ typedef enum // consult with the preferred network provider. typedef enum { - MNO_INVALID = -1, - MNO_SW_DEFAULT = 0, // Undefined / regulatory - MNO_SIM_ICCID = 1, - MNO_ATT = 2, // AT&T - MNO_VERIZON = 3, - MNO_TELSTRA = 4, - MNO_TMO = 5, // T-Mobile US - MNO_CT = 6, // China Telecom - MNO_SPRINT = 8, - MNO_VODAFONE = 19, - MNO_NTT_DOCOMO = 20, - MNO_TELUS = 21, - MNO_SOFTBANK = 28, - MNO_DT = 31, // Deutsche Telekom - MNO_US_CELLULAR = 32, - MNO_SKT = 39, - MNO_GLOBAL = 90, - MNO_STD_EUROPE = 100, - MNO_STD_EU_NOEPCO = 101 + MNO_INVALID = -1, + MNO_SW_DEFAULT = 0, // Undefined / regulatory + MNO_SIM_ICCID = 1, + MNO_ATT = 2, // AT&T + MNO_VERIZON = 3, + MNO_TELSTRA = 4, + MNO_TMO = 5, // T-Mobile US + MNO_CT = 6, // China Telecom + MNO_SPRINT = 8, + MNO_VODAFONE = 19, + MNO_NTT_DOCOMO = 20, + MNO_TELUS = 21, + MNO_SOFTBANK = 28, + MNO_DT = 31, // Deutsche Telekom + MNO_US_CELLULAR = 32, + MNO_SKT = 39, + MNO_GLOBAL = 90, + MNO_STD_EUROPE = 100, + MNO_STD_EU_NOEPCO = 101 } mobile_network_operator_t; typedef enum { - SARA_R5_ERROR_INVALID = -1, // -1 - SARA_R5_ERROR_SUCCESS = 0, // 0 - SARA_R5_ERROR_OUT_OF_MEMORY, // 1 - SARA_R5_ERROR_TIMEOUT, // 2 - SARA_R5_ERROR_UNEXPECTED_PARAM, // 3 - SARA_R5_ERROR_UNEXPECTED_RESPONSE, // 4 - SARA_R5_ERROR_NO_RESPONSE, // 5 - SARA_R5_ERROR_DEREGISTERED, // 6 - SARA_R5_ERROR_ERROR // 7 + SARA_R5_ERROR_INVALID = -1, // -1 + SARA_R5_ERROR_SUCCESS = 0, // 0 + SARA_R5_ERROR_OUT_OF_MEMORY, // 1 + SARA_R5_ERROR_TIMEOUT, // 2 + SARA_R5_ERROR_UNEXPECTED_PARAM, // 3 + SARA_R5_ERROR_UNEXPECTED_RESPONSE, // 4 + SARA_R5_ERROR_NO_RESPONSE, // 5 + SARA_R5_ERROR_DEREGISTERED, // 6 + SARA_R5_ERROR_ERROR // 7 } SARA_R5_error_t; #define SARA_R5_SUCCESS SARA_R5_ERROR_SUCCESS typedef enum { - SARA_R5_REGISTRATION_INVALID = -1, - SARA_R5_REGISTRATION_NOT_REGISTERED = 0, - SARA_R5_REGISTRATION_HOME = 1, - SARA_R5_REGISTRATION_SEARCHING = 2, - SARA_R5_REGISTRATION_DENIED = 3, - SARA_R5_REGISTRATION_UNKNOWN = 4, - SARA_R5_REGISTRATION_ROAMING = 5, - SARA_R5_REGISTRATION_HOME_SMS_ONLY = 6, - SARA_R5_REGISTRATION_ROAMING_SMS_ONLY = 7, - SARA_R5_REGISTRATION_EMERGENCY_SERV_ONLY = 8, - SARA_R5_REGISTRATION_HOME_CSFB_NOT_PREFERRED = 9, - SARA_R5_REGISTRATION_ROAMING_CSFB_NOT_PREFERRED = 10 + SARA_R5_REGISTRATION_INVALID = -1, + SARA_R5_REGISTRATION_NOT_REGISTERED = 0, + SARA_R5_REGISTRATION_HOME = 1, + SARA_R5_REGISTRATION_SEARCHING = 2, + SARA_R5_REGISTRATION_DENIED = 3, + SARA_R5_REGISTRATION_UNKNOWN = 4, + SARA_R5_REGISTRATION_ROAMING = 5, + SARA_R5_REGISTRATION_HOME_SMS_ONLY = 6, + SARA_R5_REGISTRATION_ROAMING_SMS_ONLY = 7, + SARA_R5_REGISTRATION_EMERGENCY_SERV_ONLY = 8, + SARA_R5_REGISTRATION_HOME_CSFB_NOT_PREFERRED = 9, + SARA_R5_REGISTRATION_ROAMING_CSFB_NOT_PREFERRED = 10 } SARA_R5_registration_status_t; struct DateData { - uint8_t day; - uint8_t month; - unsigned int year; + uint8_t day; + uint8_t month; + unsigned int year; }; struct TimeData { - uint8_t hour; - uint8_t minute; - uint8_t second; - unsigned int ms; - uint8_t tzh; - uint8_t tzm; + uint8_t hour; + uint8_t minute; + uint8_t second; + unsigned int ms; + uint8_t tzh; + uint8_t tzm; }; struct ClockData { - struct DateData date; - struct TimeData time; + struct DateData date; + struct TimeData time; }; struct PositionData { - float utc; - float lat; // Degrees: +/- 90 - float lon; // Degrees: +/- 180 - float alt; - char mode; - char status; + float utc; + float lat; // Degrees: +/- 90 + float lon; // Degrees: +/- 180 + float alt; + char mode; + char status; }; struct SpeedData { - float speed; // m/s - float cog; // Degrees - float magVar; // Degrees + float speed; // m/s + float cog; // Degrees + float magVar; // Degrees }; struct operator_stats { - uint8_t stat; - String shortOp; - String longOp; - unsigned long numOp; - uint8_t act; + uint8_t stat; + String shortOp; + String longOp; + unsigned long numOp; + uint8_t act; }; typedef enum { - SARA_R5_TCP = 6, - SARA_R5_UDP = 17 + SARA_R5_TCP = 6, + SARA_R5_UDP = 17 } SARA_R5_socket_protocol_t; typedef enum { - SARA_R5_MESSAGE_FORMAT_PDU = 0, - SARA_R5_MESSAGE_FORMAT_TEXT = 1 + SARA_R5_MESSAGE_FORMAT_PDU = 0, + SARA_R5_MESSAGE_FORMAT_TEXT = 1 } SARA_R5_message_format_t; typedef enum { - SARA_R5_UTIME_MODE_STOP = 0, - SARA_R5_UTIME_MODE_PPS, - SARA_R5_UTIME_MODE_ONE_SHOT, - SARA_R5_UTIME_MODE_EXT_INT + SARA_R5_UTIME_MODE_STOP = 0, + SARA_R5_UTIME_MODE_PPS, + SARA_R5_UTIME_MODE_ONE_SHOT, + SARA_R5_UTIME_MODE_EXT_INT } SARA_R5_utime_mode_t; typedef enum { - SARA_R5_UTIME_SENSOR_NONE = 0, - SARA_R5_UTIME_SENSOR_GNSS_LTE = 1, - SARA_R5_UTIME_SENSOR_LTE + SARA_R5_UTIME_SENSOR_NONE = 0, + SARA_R5_UTIME_SENSOR_GNSS_LTE = 1, + SARA_R5_UTIME_SENSOR_LTE } SARA_R5_utime_sensor_t; typedef enum { - SARA_R5_UTIME_URC_CONFIGURATION_DISABLED = 0, - SARA_R5_UTIME_URC_CONFIGURATION_ENABLED + SARA_R5_UTIME_URC_CONFIGURATION_DISABLED = 0, + SARA_R5_UTIME_URC_CONFIGURATION_ENABLED } SARA_R5_utime_urc_configuration_t; typedef enum { - SARA_R5_SIM_NOT_PRESENT = 0, - SARA_R5_SIM_PIN_NEEDED, - SARA_R5_SIM_PIN_BLOCKED, - SARA_R5_SIM_PUK_BLOCKED, - SARA_R5_SIM_NOT_OPERATIONAL, - SARA_R5_SIM_RESTRICTED, - SARA_R5_SIM_OPERATIONAL - //SARA_R5_SIM_PHONEBOOK_READY, // Not reported by SARA-R5 - //SARA_R5_SIM_USIM_PHONEBOOK_READY, // Not reported by SARA-R5 - //SARA_R5_SIM_TOOLKIT_REFRESH_SUCCESSFUL, // Not reported by SARA-R5 - //SARA_R5_SIM_TOOLKIT_REFRESH_UNSUCCESSFUL, // Not reported by SARA-R5 - //SARA_R5_SIM_PPP_CONNECTION_ACTIVE, // Not reported by SARA-R5 - //SARA_R5_SIM_VOICE_CALL_ACTIVE, // Not reported by SARA-R5 - //SARA_R5_SIM_CSD_CALL_ACTIVE // Not reported by SARA-R5 + SARA_R5_SIM_NOT_PRESENT = 0, + SARA_R5_SIM_PIN_NEEDED, + SARA_R5_SIM_PIN_BLOCKED, + SARA_R5_SIM_PUK_BLOCKED, + SARA_R5_SIM_NOT_OPERATIONAL, + SARA_R5_SIM_RESTRICTED, + SARA_R5_SIM_OPERATIONAL + //SARA_R5_SIM_PHONEBOOK_READY, // Not reported by SARA-R5 + //SARA_R5_SIM_USIM_PHONEBOOK_READY, // Not reported by SARA-R5 + //SARA_R5_SIM_TOOLKIT_REFRESH_SUCCESSFUL, // Not reported by SARA-R5 + //SARA_R5_SIM_TOOLKIT_REFRESH_UNSUCCESSFUL, // Not reported by SARA-R5 + //SARA_R5_SIM_PPP_CONNECTION_ACTIVE, // Not reported by SARA-R5 + //SARA_R5_SIM_VOICE_CALL_ACTIVE, // Not reported by SARA-R5 + //SARA_R5_SIM_CSD_CALL_ACTIVE // Not reported by SARA-R5 } SARA_R5_sim_states_t; const int RXBuffSize = 2056; const int rxWindowUS = 1000; -#define SARA_R5_NUM_PSD_PROFILES 6 // Number of supported PSD profiles +#define SARA_R5_NUM_PSD_PROFILES 6 // Number of supported PSD profiles #define SARA_R5_NUM_PDP_CONTEXT_IDENTIFIERS 11 // Number of supported PDP context identifiers -#define SARA_R5_NUM_HTTP_PROFILES 4 // Number of supported HTTP profiles +#define SARA_R5_NUM_HTTP_PROFILES 4 // Number of supported HTTP profiles typedef enum { - SARA_R5_HTTP_OP_CODE_SERVER_IP = 0, - SARA_R5_HTTP_OP_CODE_SERVER_NAME, - SARA_R5_HTTP_OP_CODE_USERNAME, - SARA_R5_HTTP_OP_CODE_PASSWORD, - SARA_R5_HTTP_OP_CODE_AUTHENTICATION, - SARA_R5_HTTP_OP_CODE_SERVER_PORT, - SARA_R5_HTTP_OP_CODE_SECURE, - SARA_R5_HTTP_OP_CODE_REQUEST_TIMEOUT, - SARA_R5_HTTP_OP_CODE_ADD_CUSTOM_HEADERS = 9 + SARA_R5_HTTP_OP_CODE_SERVER_IP = 0, + SARA_R5_HTTP_OP_CODE_SERVER_NAME, + SARA_R5_HTTP_OP_CODE_USERNAME, + SARA_R5_HTTP_OP_CODE_PASSWORD, + SARA_R5_HTTP_OP_CODE_AUTHENTICATION, + SARA_R5_HTTP_OP_CODE_SERVER_PORT, + SARA_R5_HTTP_OP_CODE_SECURE, + SARA_R5_HTTP_OP_CODE_REQUEST_TIMEOUT, + SARA_R5_HTTP_OP_CODE_ADD_CUSTOM_HEADERS = 9 } SARA_R5_http_op_codes_t; typedef enum { - SARA_R5_HTTP_COMMAND_HEAD = 0, - SARA_R5_HTTP_COMMAND_GET, - SARA_R5_HTTP_COMMAND_DELETE, - SARA_R5_HTTP_COMMAND_PUT, - SARA_R5_HTTP_COMMAND_POST_FILE, - SARA_R5_HTTP_COMMAND_POST_DATA, - SARA_R5_HTTP_COMMAND_GET_FOTA = 100 + SARA_R5_HTTP_COMMAND_HEAD = 0, + SARA_R5_HTTP_COMMAND_GET, + SARA_R5_HTTP_COMMAND_DELETE, + SARA_R5_HTTP_COMMAND_PUT, + SARA_R5_HTTP_COMMAND_POST_FILE, + SARA_R5_HTTP_COMMAND_POST_DATA, + SARA_R5_HTTP_COMMAND_GET_FOTA = 100 } SARA_R5_http_commands_t; typedef enum { - SARA_R5_HTTP_CONTENT_APPLICATION_X_WWW = 0, - SARA_R5_HTTP_CONTENT_TEXT_PLAIN, - SARA_R5_HTTP_CONTENT_APPLICATION_OCTET, - SARA_R5_HTTP_CONTENT_MULTIPART_FORM, - SARA_R5_HTTP_CONTENT_APPLICATION_JSON, - SARA_R5_HTTP_CONTENT_APPLICATION_XML, - SARA_R5_HTTP_CONTENT_USER_DEFINED + SARA_R5_HTTP_CONTENT_APPLICATION_X_WWW = 0, + SARA_R5_HTTP_CONTENT_TEXT_PLAIN, + SARA_R5_HTTP_CONTENT_APPLICATION_OCTET, + SARA_R5_HTTP_CONTENT_MULTIPART_FORM, + SARA_R5_HTTP_CONTENT_APPLICATION_JSON, + SARA_R5_HTTP_CONTENT_APPLICATION_XML, + SARA_R5_HTTP_CONTENT_USER_DEFINED } SARA_R5_http_content_types_t; typedef enum { - SARA_R5_PSD_CONFIG_PARAM_PROTOCOL = 0, - SARA_R5_PSD_CONFIG_PARAM_APN, - //SARA_R5_PSD_CONFIG_PARAM_USERNAME, // Not allowed on SARA-R5 - //SARA_R5_PSD_CONFIG_PARAM_PASSWORD, // Not allowed on SARA-R5 - SARA_R5_PSD_CONFIG_PARAM_DNS1 = 4, - SARA_R5_PSD_CONFIG_PARAM_DNS2, - //SARA_R5_PSD_CONFIG_PARAM_AUTHENTICATION, // Not allowed on SARA-R5 - //SARA_R5_PSD_CONFIG_PARAM_IP_ADDRESS, // Not allowed on SARA-R5 - //SARA_R5_PSD_CONFIG_PARAM_DATA_COMPRESSION, // Not allowed on SARA-R5 - //SARA_R5_PSD_CONFIG_PARAM_HEADER_COMPRESSION, // Not allowed on SARA-R5 - SARA_R5_PSD_CONFIG_PARAM_MAP_TO_CID = 100 + SARA_R5_PSD_CONFIG_PARAM_PROTOCOL = 0, + SARA_R5_PSD_CONFIG_PARAM_APN, + //SARA_R5_PSD_CONFIG_PARAM_USERNAME, // Not allowed on SARA-R5 + //SARA_R5_PSD_CONFIG_PARAM_PASSWORD, // Not allowed on SARA-R5 + SARA_R5_PSD_CONFIG_PARAM_DNS1 = 4, + SARA_R5_PSD_CONFIG_PARAM_DNS2, + //SARA_R5_PSD_CONFIG_PARAM_AUTHENTICATION, // Not allowed on SARA-R5 + //SARA_R5_PSD_CONFIG_PARAM_IP_ADDRESS, // Not allowed on SARA-R5 + //SARA_R5_PSD_CONFIG_PARAM_DATA_COMPRESSION, // Not allowed on SARA-R5 + //SARA_R5_PSD_CONFIG_PARAM_HEADER_COMPRESSION, // Not allowed on SARA-R5 + SARA_R5_PSD_CONFIG_PARAM_MAP_TO_CID = 100 } SARA_R5_pdp_configuration_parameter_t; typedef enum { - SARA_R5_PSD_PROTOCOL_IPV4 = 0, - SARA_R5_PSD_PROTOCOL_IPV6, - SARA_R5_PSD_PROTOCOL_IPV4V6_V4_PREF, - SARA_R5_PSD_PROTOCOL_IPV4V6_V6_PREF + SARA_R5_PSD_PROTOCOL_IPV4 = 0, + SARA_R5_PSD_PROTOCOL_IPV6, + SARA_R5_PSD_PROTOCOL_IPV4V6_V4_PREF, + SARA_R5_PSD_PROTOCOL_IPV4V6_V6_PREF } SARA_R5_pdp_protocol_type_t; typedef enum @@ -431,369 +433,384 @@ typedef enum typedef enum { - MINIMUM_FUNCTIONALITY = 0, // (disable both transmit and receive RF circuits by deactivating both CS and PS services) - FULL_FUNCTIONALITY = 1, - AIRPLANE_MODE = 4, - SIM_TOOLKIT_ENABLE_DEDICATED = 6, - SIM_TOOLKIT_DISABLE_DEDICATED = 7, - SIM_TOOLKIT_ENABLE_RAW = 9, - FAST_SAFE_POWER_OFF = 10, - //SILENT_RESET_WITHOUT_SIM = 15, // Not supported on SARA-R5 - SILENT_RESET_WITH_SIM = 16 - //MINIMUM_FUNCTIONALITY = 19, // Not supported on SARA-R5 - //DEEP_LOW_POWER_STATE = 127 // Not supported on SARA-R5 + MINIMUM_FUNCTIONALITY = 0, // (disable both transmit and receive RF circuits by deactivating both CS and PS services) + FULL_FUNCTIONALITY = 1, + AIRPLANE_MODE = 4, + SIM_TOOLKIT_ENABLE_DEDICATED = 6, + SIM_TOOLKIT_DISABLE_DEDICATED = 7, + SIM_TOOLKIT_ENABLE_RAW = 9, + FAST_SAFE_POWER_OFF = 10, + //SILENT_RESET_WITHOUT_SIM = 15, // Not supported on SARA-R5 + SILENT_RESET_WITH_SIM = 16 + //MINIMUM_FUNCTIONALITY = 19, // Not supported on SARA-R5 + //DEEP_LOW_POWER_STATE = 127 // Not supported on SARA-R5 } SARA_R5_functionality_t; class SARA_R5 : public Print { public: + char saraRXBuffer[RXBuffSize]; + char saraResponseBacklog[RXBuffSize]; - char saraRXBuffer[RXBuffSize]; - char saraResponseBacklog[RXBuffSize]; + // Constructor + SARA_R5(int powerPin = SARA_R5_POWER_PIN, int resetPin = SARA_R5_RESET_PIN, uint8_t maxInitDepth = 9); - // Constructor - SARA_R5(int powerPin = SARA_R5_POWER_PIN, int resetPin = SARA_R5_RESET_PIN, uint8_t maxInitDepth = 9); - - // Begin -- initialize BT module and ensure it's connected + // Begin -- initialize BT module and ensure it's connected #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - bool begin(SoftwareSerial &softSerial, unsigned long baud = 9600); + bool begin(SoftwareSerial &softSerial, unsigned long baud = 9600); #endif - bool begin(HardwareSerial &hardSerial, unsigned long baud = 9600); - - // Debug prints - void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used. - - // Invert the polarity of the power pin - if required - // Normally the SARA's power pin is pulled low and released to toggle the power - // But the Asset Tracker needs this to be pulled high and released instead - void invertPowerPin(bool invert = false); - - // Loop polling and polling setup - bool bufferedPoll(void); - bool processReadEvent(char* event); - bool poll(void); - void setSocketReadCallback(void (*socketReadCallback)(int, String)); - void setSocketCloseCallback(void (*socketCloseCallback)(int)); - void setGpsReadCallback(void (*gpsRequestCallback)(ClockData time, - PositionData gps, SpeedData spd, unsigned long uncertainty)); - void setSIMstateReportCallback(void (*simStateRequestCallback)(SARA_R5_sim_states_t state)); - void setPSDActionCallback(void (*psdActionRequestCallback)(int result, IPAddress ip)); - void setPingCallback(void (*pingRequestCallback)(int retry, int p_size, String remote_hostname, IPAddress ip, int ttl, long rtt)); - void setHTTPCommandCallback(void (*httpCommandRequestCallback)(int profile, int command, int result)); - - // Direct write/print to cell serial port - virtual size_t write(uint8_t c); - virtual size_t write(const char *str); - virtual size_t write(const char *buffer, size_t size); - - // General AT Commands - SARA_R5_error_t at(void); - SARA_R5_error_t enableEcho(bool enable = true); - String getManufacturerID(void); - String getModelID(void); - String getFirmwareVersion(void); - String getSerialNo(void); - String getIMEI(void); - String getIMSI(void); - String getCCID(void); - String getSubscriberNo(void); - String getCapabilities(void); - - // Control and status AT commands - SARA_R5_error_t reset(void); - String clock(void); - // TODO: Return a clock struct - SARA_R5_error_t clock(uint8_t *y, uint8_t *mo, uint8_t *d, - uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz); - SARA_R5_error_t autoTimeZone(bool enable); - SARA_R5_error_t setUtimeMode(SARA_R5_utime_mode_t mode = SARA_R5_UTIME_MODE_PPS, SARA_R5_utime_sensor_t sensor = SARA_R5_UTIME_SENSOR_GNSS_LTE); - SARA_R5_error_t getUtimeMode(SARA_R5_utime_mode_t *mode, SARA_R5_utime_sensor_t *sensor); - SARA_R5_error_t setUtimeIndication(SARA_R5_utime_urc_configuration_t config = SARA_R5_UTIME_URC_CONFIGURATION_ENABLED); - SARA_R5_error_t getUtimeIndication(SARA_R5_utime_urc_configuration_t *config); - SARA_R5_error_t setUtimeConfiguration(int32_t offsetNanoseconds = 0, int32_t offsetSeconds = 0); - SARA_R5_error_t getUtimeConfiguration(int32_t *offsetNanoseconds, int32_t *offsetSeconds); - - // Network service AT commands - int8_t rssi(void); - SARA_R5_registration_status_t registration(void); - bool setNetworkProfile(mobile_network_operator_t mno, bool autoReset = false, bool urcNotification = false); - mobile_network_operator_t getNetworkProfile(void); - typedef enum - { - PDP_TYPE_INVALID = -1, - PDP_TYPE_IP = 0, - PDP_TYPE_NONIP = 1, - PDP_TYPE_IPV4V6 = 2, - PDP_TYPE_IPV6 = 3 - } SARA_R5_pdp_type; - SARA_R5_error_t setAPN(String apn, uint8_t cid = 1, SARA_R5_pdp_type pdpType = PDP_TYPE_IP); // Set the Access Point Name - SARA_R5_error_t getAPN(int cid, String *apn, IPAddress *ip); // Return the apn and IP address for the chosen context identifier - - // SIM - // Status report Mode: - // Bit States reported - // 0 Reports the (U)SIM initialization status ('s from 0 to 6 may be reported) - // 1 Reports the (U)SIM phonebook initialization status ('s from 7 to 8 may be reported) - // 2 Reports the (U)SIM toolkit REFRESH proactive command execution result ('s from 9 to 13 may be reported) - // Note: For the SARA-R5: =7, 8, 9, 10, 11, 12 and 13 are not reported. - SARA_R5_error_t setSIMstateReportingMode(int mode); - SARA_R5_error_t getSIMstateReportingMode(int *mode); - - typedef enum - { - L2P_DEFAULT, - L2P_PPP, - L2P_M_HEX, - L2P_M_RAW_IP, - L2P_M_OPT_PPP - } SARA_R5_l2p_t; - SARA_R5_error_t enterPPP(uint8_t cid = 1, char dialing_type_char = 0, - unsigned long dialNumber = 99, SARA_R5_l2p_t l2p = L2P_DEFAULT); - - uint8_t getOperators(struct operator_stats *op, int maxOps = 3); - SARA_R5_error_t registerOperator(struct operator_stats oper); - SARA_R5_error_t automaticOperatorSelection(); - SARA_R5_error_t getOperator(String *oper); - SARA_R5_error_t deregisterOperator(void); - - // SMS -- Short Messages Service - SARA_R5_error_t setSMSMessageFormat(SARA_R5_message_format_t textMode = SARA_R5_MESSAGE_FORMAT_TEXT); - SARA_R5_error_t sendSMS(String number, String message); - SARA_R5_error_t getPreferredMessageStorage(int *used, int *total, String memory = "ME"); - SARA_R5_error_t readSMSmessage(int location, String *unread, String *from, String *dateTime, String *message); - - // V24 Control and V25ter (UART interface) AT commands - SARA_R5_error_t setBaud(unsigned long baud); - SARA_R5_error_t setFlowControl(SARA_R5_flow_control_t value = SARA_R5_ENABLE_FLOW_CONTROL); - - // GPIO - // GPIO pin map - typedef enum - { - GPIO1 = 16, - GPIO2 = 23, - GPIO3 = 24, - GPIO4 = 25, - GPIO5 = 42, - GPIO6 = 19 - } SARA_R5_gpio_t; - // GPIO pin modes - typedef enum - { - GPIO_MODE_INVALID = -1, - GPIO_OUTPUT = 0, - GPIO_INPUT, - NETWORK_STATUS, - GNSS_SUPPLY_ENABLE, - GNSS_DATA_READY, - GNSS_RTC_SHARING, - JAMMING_DETECTION, - SIM_CARD_DETECTION, - HEADSET_DETECTION, - GSM_TX_BURST_INDICATION, - MODULE_STATUS_INDICATION, - MODULE_OPERATING_MODE_INDICATION, - I2S_DIGITAL_AUDIO_INTERFACE, - SPI_SERIAL_INTERFACE, - MASTER_CLOCK_GENRATION, - UART_INTERFACE, - WIFI_ENABLE, - RING_INDICATION = 18, - LAST_GASP_ENABLE, - EXTERNAL_GNSS_ANTENNA, - TIME_PULSE_GNSS, - TIME_PULSE_OUTPUT, - TIMESTAMP, - FAST_POWER_OFF, - LWM2M_PULSE, - HARDWARE_FLOW_CONTROL, - ANTENNA_TUNING, - EXT_GNSS_TIME_PULSE, - EXT_GNSS_TIMESTAMP, - DTR_MODE, - KHZ_32768_OUT = 32, - PAD_DISABLED = 255 - } SARA_R5_gpio_mode_t; - SARA_R5_error_t setGpioMode(SARA_R5_gpio_t gpio, SARA_R5_gpio_mode_t mode, int value = 0); - SARA_R5_gpio_mode_t getGpioMode(SARA_R5_gpio_t gpio); - - // IP Transport Layer - int socketOpen(SARA_R5_socket_protocol_t protocol, unsigned int localPort = 0); - SARA_R5_error_t socketClose(int socket, unsigned long timeout = SARA_R5_2_MIN_TIMEOUT); - SARA_R5_error_t socketConnect(int socket, const char *address, unsigned int port); - SARA_R5_error_t socketWrite(int socket, const char *str); - SARA_R5_error_t socketWrite(int socket, String str); - SARA_R5_error_t socketWriteUDP(int socket, const char *address, int port, const char *str, int len = -1); - SARA_R5_error_t socketWriteUDP(int socket, String address, int port, String str, int len = -1); - SARA_R5_error_t socketRead(int socket, int length, char *readDest); - SARA_R5_error_t socketReadUDP(int socket, int length, char *readDest); - SARA_R5_error_t socketListen(int socket, unsigned int port); - SARA_R5_error_t socketDirectLinkMode(int socket); - SARA_R5_error_t socketDirectLinkTimeTrigger(int socket, unsigned long timerTrigger); - SARA_R5_error_t socketDirectLinkDataLengthTrigger(int socket, int dataLengthTrigger); - SARA_R5_error_t socketDirectLinkCharacterTrigger(int socket, int characterTrigger); - SARA_R5_error_t socketDirectLinkCongestionTimer(int socket, unsigned long congestionTimer); - int socketGetLastError(); - IPAddress lastRemoteIP(void); - - // Ping - SARA_R5_error_t ping(String remote_host, int retry = 4, int p_size = 32, unsigned long timeout = 5000, int ttl = 32); - - // HTTP - SARA_R5_error_t resetHTTPprofile(int profile); // Reset the HTTP profile. Note: The configured HTTP profile parameters are not saved in the non volatile memory. - SARA_R5_error_t setHTTPserverIPaddress(int profile, IPAddress address); // Default: empty string - SARA_R5_error_t setHTTPserverName(int profile, String server); // Default: empty string - SARA_R5_error_t setHTTPusername(int profile, String username); // Default: empty string - SARA_R5_error_t setHTTPpassword(int profile, String password); // Default: empty string - SARA_R5_error_t setHTTPauthentication(int profile, bool authenticate); // Default: no authentication - SARA_R5_error_t setHTTPserverPort(int profile, int port); // Default: 80 - SARA_R5_error_t setHTTPsecure(int profile, bool secure); // Default: disabled (HTTP on port 80). Set to true for HTTPS on port 443 - // TO DO: Add custom request headers - SARA_R5_error_t getHTTPprotocolError(int profile, int *error_class, int *error_code); // Read the most recent HTTP protocol error for this profile - SARA_R5_error_t sendHTTPGET(int profile, String path, String responseFilename); - SARA_R5_error_t sendHTTPPOSTdata(int profile, String path, String responseFilename, String data, SARA_R5_http_content_types_t httpContentType); - - // Packet Switched Data - SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, int value); // Set parameters in the chosen PSD profile - SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, SARA_R5_pdp_protocol_type_t value); // Set parameters in the chosen PSD profile - SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, String value); // Set parameters in the chosen PSD profile - SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, IPAddress value); // Set parameters in the chosen PSD profile - SARA_R5_error_t performPDPaction(int profile, SARA_R5_pdp_actions_t action); // Performs the requested action for the specified PSD profile. - SARA_R5_error_t activatePDPcontext(bool status, int cid = -1); // Activates or deactivates the specified PDP context. Default to all (cid = -1) - - // GPS - typedef enum - { - GNSS_SYSTEM_GPS = 1, - GNSS_SYSTEM_SBAS = 2, - GNSS_SYSTEM_GALILEO = 4, - GNSS_SYSTEM_BEIDOU = 8, - GNSS_SYSTEM_IMES = 16, - GNSS_SYSTEM_QZSS = 32, - GNSS_SYSTEM_GLONASS = 64 - } gnss_system_t; - typedef enum - { - GNSS_AIDING_MODE_NONE = 0, - GNSS_AIDING_MODE_AUTOMATIC = 1, - GNSS_AIDING_MODE_ASSISTNOW_OFFLINE = 2, - GNSS_AIDING_MODE_ASSISTNOW_ONLINE = 4, - GNSS_AIDING_MODE_ASSISTNOW_AUTONOMOUS = 8 - } gnss_aiding_mode_t; - bool isGPSon(void); - SARA_R5_error_t gpsPower(bool enable = true, - gnss_system_t gnss_sys = GNSS_SYSTEM_GPS, - gnss_aiding_mode_t gnss_aiding = GNSS_AIDING_MODE_AUTOMATIC); - //SARA_R5_error_t gpsEnableClock(bool enable = true); - //SARA_R5_error_t gpsGetClock(struct ClockData *clock); - //SARA_R5_error_t gpsEnableFix(bool enable = true); - //SARA_R5_error_t gpsGetFix(float *lat, float *lon, unsigned int *alt, uint8_t *quality, uint8_t *sat); - //SARA_R5_error_t gpsGetFix(struct PositionData *pos); - //SARA_R5_error_t gpsEnablePos(bool enable = true); - //SARA_R5_error_t gpsGetPos(struct PositionData *pos); - //SARA_R5_error_t gpsEnableSat(bool enable = true); - //SARA_R5_error_t gpsGetSat(uint8_t *sats); - SARA_R5_error_t gpsEnableRmc(bool enable = true); - SARA_R5_error_t gpsGetRmc(struct PositionData *pos, struct SpeedData *speed, struct ClockData *clk, bool *valid); - //SARA_R5_error_t gpsEnableSpeed(bool enable = true); - //SARA_R5_error_t gpsGetSpeed(struct SpeedData *speed); - - SARA_R5_error_t gpsRequest(unsigned int timeout, uint32_t accuracy, bool detailed = true, unsigned int sensor = 3); - - //CellLocate - SARA_R5_error_t gpsAidingServerConf(const char *primaryServer, const char *secondaryServer, const char *authToken, - unsigned int days = 14, unsigned int period = 4, unsigned int resolution = 1, - unsigned int gnssTypes = 65, unsigned int mode = 0, unsigned int dataType = 15); - - // File system - SARA_R5_error_t getFileContents(String filename, String *contents); - - // Functionality - SARA_R5_error_t functionality(SARA_R5_functionality_t function = FULL_FUNCTIONALITY); - - // Send a custom command with an expected (potentially partial) response, store entire response - SARA_R5_error_t sendCustomCommandWithResponse(const char *command, const char *expectedResponse, - char *responseDest, unsigned long commandTimeout = SARA_R5_STANDARD_RESPONSE_TIMEOUT, bool at = true); + bool begin(HardwareSerial &hardSerial, unsigned long baud = 9600); + + // Debug prints + void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used. + + // Invert the polarity of the power pin - if required + // Normally the SARA's power pin is pulled low and released to toggle the power + // But the Asset Tracker needs this to be pulled high and released instead + void invertPowerPin(bool invert = false); + + SARA_R5_error_t modulePowerOff(void); // Graceful disconnect and shutdown using +CPWROFF. + void modulePowerOn(void); // Requires access to the PWR_ON pin + + // Loop polling and polling setup + + // This function was originally written by Matthew Menze for the LTE Shield (SARA-R4) library + // See: https://github.com/sparkfun/SparkFun_LTE_Shield_Arduino_Library/pull/8 + // It does the same job as ::poll but also processed any 'old' data stored in the backlog first + // It also has a built-in timeout - which ::poll does not + bool bufferedPoll(void); + + // This is the original poll function. + // It is 'blocking' - it does not return when serial data is available until it receives a `\n`. + // ::bufferedPoll is the new improved version. It processes any data in the backlog and includes a timeout. + bool poll(void); + + // Callbacks (called during polling) + void setSocketListenCallback(void (*socketListenCallback)(int, IPAddress, unsigned int, int, IPAddress, unsigned int)); + void setSocketReadCallback(void (*socketReadCallback)(int, String)); + void setSocketCloseCallback(void (*socketCloseCallback)(int)); + void setGpsReadCallback(void (*gpsRequestCallback)(ClockData time, + PositionData gps, SpeedData spd, unsigned long uncertainty)); + void setSIMstateReportCallback(void (*simStateRequestCallback)(SARA_R5_sim_states_t state)); + void setPSDActionCallback(void (*psdActionRequestCallback)(int result, IPAddress ip)); + void setPingCallback(void (*pingRequestCallback)(int retry, int p_size, String remote_hostname, IPAddress ip, int ttl, long rtt)); + void setHTTPCommandCallback(void (*httpCommandRequestCallback)(int profile, int command, int result)); + + // Direct write/print to cell serial port + virtual size_t write(uint8_t c); + virtual size_t write(const char *str); + virtual size_t write(const char *buffer, size_t size); + + // General AT Commands + SARA_R5_error_t at(void); + SARA_R5_error_t enableEcho(bool enable = true); + String getManufacturerID(void); + String getModelID(void); + String getFirmwareVersion(void); + String getSerialNo(void); + String getIMEI(void); + String getIMSI(void); + String getCCID(void); + String getSubscriberNo(void); + String getCapabilities(void); + + // Control and status AT commands + SARA_R5_error_t reset(void); + String clock(void); + // TODO: Return a clock struct + SARA_R5_error_t clock(uint8_t *y, uint8_t *mo, uint8_t *d, + uint8_t *h, uint8_t *min, uint8_t *s, uint8_t *tz); + SARA_R5_error_t autoTimeZone(bool enable); + SARA_R5_error_t setUtimeMode(SARA_R5_utime_mode_t mode = SARA_R5_UTIME_MODE_PPS, SARA_R5_utime_sensor_t sensor = SARA_R5_UTIME_SENSOR_GNSS_LTE); + SARA_R5_error_t getUtimeMode(SARA_R5_utime_mode_t *mode, SARA_R5_utime_sensor_t *sensor); + SARA_R5_error_t setUtimeIndication(SARA_R5_utime_urc_configuration_t config = SARA_R5_UTIME_URC_CONFIGURATION_ENABLED); + SARA_R5_error_t getUtimeIndication(SARA_R5_utime_urc_configuration_t *config); + SARA_R5_error_t setUtimeConfiguration(int32_t offsetNanoseconds = 0, int32_t offsetSeconds = 0); + SARA_R5_error_t getUtimeConfiguration(int32_t *offsetNanoseconds, int32_t *offsetSeconds); + + // Network service AT commands + int8_t rssi(void); + SARA_R5_registration_status_t registration(void); + bool setNetworkProfile(mobile_network_operator_t mno, bool autoReset = false, bool urcNotification = false); + mobile_network_operator_t getNetworkProfile(void); + typedef enum + { + PDP_TYPE_INVALID = -1, + PDP_TYPE_IP = 0, + PDP_TYPE_NONIP = 1, + PDP_TYPE_IPV4V6 = 2, + PDP_TYPE_IPV6 = 3 + } SARA_R5_pdp_type; + SARA_R5_error_t setAPN(String apn, uint8_t cid = 1, SARA_R5_pdp_type pdpType = PDP_TYPE_IP); // Set the Access Point Name + SARA_R5_error_t getAPN(int cid, String *apn, IPAddress *ip); // Return the apn and IP address for the chosen context identifier + + // SIM + // Status report Mode: + // Bit States reported + // 0 Reports the (U)SIM initialization status ('s from 0 to 6 may be reported) + // 1 Reports the (U)SIM phonebook initialization status ('s from 7 to 8 may be reported) + // 2 Reports the (U)SIM toolkit REFRESH proactive command execution result ('s from 9 to 13 may be reported) + // Note: For the SARA-R5: =7, 8, 9, 10, 11, 12 and 13 are not reported. + SARA_R5_error_t setSIMstateReportingMode(int mode); + SARA_R5_error_t getSIMstateReportingMode(int *mode); + + typedef enum + { + L2P_DEFAULT, + L2P_PPP, + L2P_M_HEX, + L2P_M_RAW_IP, + L2P_M_OPT_PPP + } SARA_R5_l2p_t; + SARA_R5_error_t enterPPP(uint8_t cid = 1, char dialing_type_char = 0, + unsigned long dialNumber = 99, SARA_R5_l2p_t l2p = L2P_DEFAULT); + + uint8_t getOperators(struct operator_stats *op, int maxOps = 3); + SARA_R5_error_t registerOperator(struct operator_stats oper); + SARA_R5_error_t automaticOperatorSelection(); + SARA_R5_error_t getOperator(String *oper); + SARA_R5_error_t deregisterOperator(void); + + // SMS -- Short Messages Service + SARA_R5_error_t setSMSMessageFormat(SARA_R5_message_format_t textMode = SARA_R5_MESSAGE_FORMAT_TEXT); + SARA_R5_error_t sendSMS(String number, String message); + SARA_R5_error_t getPreferredMessageStorage(int *used, int *total, String memory = "ME"); + SARA_R5_error_t readSMSmessage(int location, String *unread, String *from, String *dateTime, String *message); + + // V24 Control and V25ter (UART interface) AT commands + SARA_R5_error_t setBaud(unsigned long baud); + SARA_R5_error_t setFlowControl(SARA_R5_flow_control_t value = SARA_R5_ENABLE_FLOW_CONTROL); + + // GPIO + // GPIO pin map + typedef enum + { + GPIO1 = 16, + GPIO2 = 23, + GPIO3 = 24, + GPIO4 = 25, + GPIO5 = 42, + GPIO6 = 19 + } SARA_R5_gpio_t; + // GPIO pin modes + typedef enum + { + GPIO_MODE_INVALID = -1, + GPIO_OUTPUT = 0, + GPIO_INPUT, + NETWORK_STATUS, + GNSS_SUPPLY_ENABLE, + GNSS_DATA_READY, + GNSS_RTC_SHARING, + JAMMING_DETECTION, + SIM_CARD_DETECTION, + HEADSET_DETECTION, + GSM_TX_BURST_INDICATION, + MODULE_STATUS_INDICATION, + MODULE_OPERATING_MODE_INDICATION, + I2S_DIGITAL_AUDIO_INTERFACE, + SPI_SERIAL_INTERFACE, + MASTER_CLOCK_GENRATION, + UART_INTERFACE, + WIFI_ENABLE, + RING_INDICATION = 18, + LAST_GASP_ENABLE, + EXTERNAL_GNSS_ANTENNA, + TIME_PULSE_GNSS, + TIME_PULSE_OUTPUT, + TIMESTAMP, + FAST_POWER_OFF, + LWM2M_PULSE, + HARDWARE_FLOW_CONTROL, + ANTENNA_TUNING, + EXT_GNSS_TIME_PULSE, + EXT_GNSS_TIMESTAMP, + DTR_MODE, + KHZ_32768_OUT = 32, + PAD_DISABLED = 255 + } SARA_R5_gpio_mode_t; + SARA_R5_error_t setGpioMode(SARA_R5_gpio_t gpio, SARA_R5_gpio_mode_t mode, int value = 0); + SARA_R5_gpio_mode_t getGpioMode(SARA_R5_gpio_t gpio); + + // IP Transport Layer + int socketOpen(SARA_R5_socket_protocol_t protocol, unsigned int localPort = 0); + SARA_R5_error_t socketClose(int socket, unsigned long timeout = SARA_R5_2_MIN_TIMEOUT); + SARA_R5_error_t socketConnect(int socket, const char *address, unsigned int port); + SARA_R5_error_t socketWrite(int socket, const char *str); + SARA_R5_error_t socketWrite(int socket, String str); + SARA_R5_error_t socketWriteUDP(int socket, const char *address, int port, const char *str, int len = -1); + SARA_R5_error_t socketWriteUDP(int socket, String address, int port, String str, int len = -1); + SARA_R5_error_t socketRead(int socket, int length, char *readDest); + SARA_R5_error_t socketReadUDP(int socket, int length, char *readDest); + SARA_R5_error_t socketListen(int socket, unsigned int port); + SARA_R5_error_t socketDirectLinkMode(int socket); + SARA_R5_error_t socketDirectLinkTimeTrigger(int socket, unsigned long timerTrigger); + SARA_R5_error_t socketDirectLinkDataLengthTrigger(int socket, int dataLengthTrigger); + SARA_R5_error_t socketDirectLinkCharacterTrigger(int socket, int characterTrigger); + SARA_R5_error_t socketDirectLinkCongestionTimer(int socket, unsigned long congestionTimer); + int socketGetLastError(); + IPAddress lastRemoteIP(void); + + // Ping + SARA_R5_error_t ping(String remote_host, int retry = 4, int p_size = 32, unsigned long timeout = 5000, int ttl = 32); + + // HTTP + SARA_R5_error_t resetHTTPprofile(int profile); // Reset the HTTP profile. Note: The configured HTTP profile parameters are not saved in the non volatile memory. + SARA_R5_error_t setHTTPserverIPaddress(int profile, IPAddress address); // Default: empty string + SARA_R5_error_t setHTTPserverName(int profile, String server); // Default: empty string + SARA_R5_error_t setHTTPusername(int profile, String username); // Default: empty string + SARA_R5_error_t setHTTPpassword(int profile, String password); // Default: empty string + SARA_R5_error_t setHTTPauthentication(int profile, bool authenticate); // Default: no authentication + SARA_R5_error_t setHTTPserverPort(int profile, int port); // Default: 80 + SARA_R5_error_t setHTTPsecure(int profile, bool secure); // Default: disabled (HTTP on port 80). Set to true for HTTPS on port 443 + // TO DO: Add custom request headers + SARA_R5_error_t getHTTPprotocolError(int profile, int *error_class, int *error_code); // Read the most recent HTTP protocol error for this profile + SARA_R5_error_t sendHTTPGET(int profile, String path, String responseFilename); + SARA_R5_error_t sendHTTPPOSTdata(int profile, String path, String responseFilename, String data, SARA_R5_http_content_types_t httpContentType); + + // Packet Switched Data + SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, int value); // Set parameters in the chosen PSD profile + SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, SARA_R5_pdp_protocol_type_t value); // Set parameters in the chosen PSD profile + SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, String value); // Set parameters in the chosen PSD profile + SARA_R5_error_t setPDPconfiguration(int profile, SARA_R5_pdp_configuration_parameter_t parameter, IPAddress value); // Set parameters in the chosen PSD profile + SARA_R5_error_t performPDPaction(int profile, SARA_R5_pdp_actions_t action); // Performs the requested action for the specified PSD profile. + SARA_R5_error_t activatePDPcontext(bool status, int cid = -1); // Activates or deactivates the specified PDP context. Default to all (cid = -1) + + // GPS + typedef enum + { + GNSS_SYSTEM_GPS = 1, + GNSS_SYSTEM_SBAS = 2, + GNSS_SYSTEM_GALILEO = 4, + GNSS_SYSTEM_BEIDOU = 8, + GNSS_SYSTEM_IMES = 16, + GNSS_SYSTEM_QZSS = 32, + GNSS_SYSTEM_GLONASS = 64 + } gnss_system_t; + typedef enum + { + GNSS_AIDING_MODE_NONE = 0, + GNSS_AIDING_MODE_AUTOMATIC = 1, + GNSS_AIDING_MODE_ASSISTNOW_OFFLINE = 2, + GNSS_AIDING_MODE_ASSISTNOW_ONLINE = 4, + GNSS_AIDING_MODE_ASSISTNOW_AUTONOMOUS = 8 + } gnss_aiding_mode_t; + bool isGPSon(void); + SARA_R5_error_t gpsPower(bool enable = true, + gnss_system_t gnss_sys = GNSS_SYSTEM_GPS, + gnss_aiding_mode_t gnss_aiding = GNSS_AIDING_MODE_AUTOMATIC); + //SARA_R5_error_t gpsEnableClock(bool enable = true); + //SARA_R5_error_t gpsGetClock(struct ClockData *clock); + //SARA_R5_error_t gpsEnableFix(bool enable = true); + //SARA_R5_error_t gpsGetFix(float *lat, float *lon, unsigned int *alt, uint8_t *quality, uint8_t *sat); + //SARA_R5_error_t gpsGetFix(struct PositionData *pos); + //SARA_R5_error_t gpsEnablePos(bool enable = true); + //SARA_R5_error_t gpsGetPos(struct PositionData *pos); + //SARA_R5_error_t gpsEnableSat(bool enable = true); + //SARA_R5_error_t gpsGetSat(uint8_t *sats); + SARA_R5_error_t gpsEnableRmc(bool enable = true); + SARA_R5_error_t gpsGetRmc(struct PositionData *pos, struct SpeedData *speed, struct ClockData *clk, bool *valid); + //SARA_R5_error_t gpsEnableSpeed(bool enable = true); + //SARA_R5_error_t gpsGetSpeed(struct SpeedData *speed); + + SARA_R5_error_t gpsRequest(unsigned int timeout, uint32_t accuracy, bool detailed = true, unsigned int sensor = 3); + + //CellLocate + SARA_R5_error_t gpsAidingServerConf(const char *primaryServer, const char *secondaryServer, const char *authToken, + unsigned int days = 14, unsigned int period = 4, unsigned int resolution = 1, + unsigned int gnssTypes = 65, unsigned int mode = 0, unsigned int dataType = 15); + + // File system + SARA_R5_error_t getFileContents(String filename, String *contents); + + // Functionality + SARA_R5_error_t functionality(SARA_R5_functionality_t function = FULL_FUNCTIONALITY); + + // Send a custom command with an expected (potentially partial) response, store entire response + SARA_R5_error_t sendCustomCommandWithResponse(const char *command, const char *expectedResponse, + char *responseDest, unsigned long commandTimeout = SARA_R5_STANDARD_RESPONSE_TIMEOUT, bool at = true); private: - HardwareSerial *_hardSerial; + HardwareSerial *_hardSerial; #ifdef SARA_R5_SOFTWARE_SERIAL_ENABLED - SoftwareSerial *_softSerial; + SoftwareSerial *_softSerial; #endif - Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial. - bool _printDebug = false; //Flag to print debugging variables - - int _powerPin; - int _resetPin; - bool _invertPowerPin = false; - - unsigned long _baud; - IPAddress _lastRemoteIP; - IPAddress _lastLocalIP; - uint8_t _maxInitDepth; - uint8_t _currentInitDepth = 0; - - void (*_socketReadCallback)(int, String); - void (*_socketCloseCallback)(int); - void (*_gpsRequestCallback)(ClockData, PositionData, SpeedData, unsigned long); - void (*_simStateReportCallback)(SARA_R5_sim_states_t); - void (*_psdActionRequestCallback)(int, IPAddress); - void (*_pingRequestCallback)(int, int, String, IPAddress, int, long); - void (*_httpCommandRequestCallback)(int, int, int); - - typedef enum - { - SARA_R5_INIT_STANDARD, - SARA_R5_INIT_AUTOBAUD, - SARA_R5_INIT_RESET - } SARA_R5_init_type_t; - - SARA_R5_error_t init(unsigned long baud, SARA_R5_init_type_t initType = SARA_R5_INIT_STANDARD); - - void powerOn(void); - - void hwReset(void); - - SARA_R5_error_t setMNOprofile(mobile_network_operator_t mno, bool autoReset = false, bool urcNotification = false); - SARA_R5_error_t getMNOprofile(mobile_network_operator_t *mno); - - // Wait for an expected response (don't send a command) - SARA_R5_error_t waitForResponse(const char *expectedResponse, const char *expectedError, uint16_t timeout); - - // Send command with an expected (potentially partial) response, store entire response - SARA_R5_error_t sendCommandWithResponse(const char *command, const char *expectedResponse, - char *responseDest, unsigned long commandTimeout, bool at = true); - - // Send a command -- prepend AT if at is true - int sendCommand(const char *command, bool at); - - SARA_R5_error_t parseSocketReadIndication(int socket, int length); - SARA_R5_error_t parseSocketReadIndicationUDP(int socket, int length); - SARA_R5_error_t parseSocketListenIndication(IPAddress localIP, IPAddress remoteIP); - SARA_R5_error_t parseSocketCloseIndication(String *closeIndication); - - // UART Functions - size_t hwPrint(const char *s); - size_t hwWriteData(const char* buff, int len); - size_t hwWrite(const char c); - int readAvailable(char *inString); - char readChar(void); - int hwAvailable(void); - void beginSerial(unsigned long baud); - void setTimeout(unsigned long timeout); - bool find(char *target); - - SARA_R5_error_t autobaud(unsigned long desiredBaud); - - char *sara_r5_calloc_char(size_t num); - - void pruneBacklog(void); - - // GPS Helper functions - char *readDataUntil(char *destination, unsigned int destSize, char *source, char delimiter); - bool parseGPRMCString(char *rmcString, PositionData *pos, ClockData *clk, SpeedData *spd); - + Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial. + bool _printDebug = false; //Flag to print debugging variables + + int _powerPin; + int _resetPin; + bool _invertPowerPin = false; + + unsigned long _baud; + IPAddress _lastRemoteIP; + IPAddress _lastLocalIP; + uint8_t _maxInitDepth; + uint8_t _currentInitDepth = 0; + + void (*_socketListenCallback)(int, IPAddress, unsigned int, int, IPAddress, unsigned int); + void (*_socketReadCallback)(int, String); + void (*_socketCloseCallback)(int); + void (*_gpsRequestCallback)(ClockData, PositionData, SpeedData, unsigned long); + void (*_simStateReportCallback)(SARA_R5_sim_states_t); + void (*_psdActionRequestCallback)(int, IPAddress); + void (*_pingRequestCallback)(int, int, String, IPAddress, int, long); + void (*_httpCommandRequestCallback)(int, int, int); + + typedef enum + { + SARA_R5_INIT_STANDARD, + SARA_R5_INIT_AUTOBAUD, + SARA_R5_INIT_RESET + } SARA_R5_init_type_t; + + SARA_R5_error_t init(unsigned long baud, SARA_R5_init_type_t initType = SARA_R5_INIT_STANDARD); + + void powerOn(void); // Brief pulse on PWR_ON to turn module back on + void powerOff(void); // Long pulse on PWR_ON to do a graceful shutdown. Note modulePowerOff (+CPWROFF) is preferred. + + void hwReset(void); + + SARA_R5_error_t setMNOprofile(mobile_network_operator_t mno, bool autoReset = false, bool urcNotification = false); + SARA_R5_error_t getMNOprofile(mobile_network_operator_t *mno); + + // Wait for an expected response (don't send a command) + SARA_R5_error_t waitForResponse(const char *expectedResponse, const char *expectedError, uint16_t timeout); + + // Send command with an expected (potentially partial) response, store entire response + SARA_R5_error_t sendCommandWithResponse(const char *command, const char *expectedResponse, + char *responseDest, unsigned long commandTimeout, bool at = true); + + // Send a command -- prepend AT if at is true + int sendCommand(const char *command, bool at); + + SARA_R5_error_t parseSocketReadIndication(int socket, int length); + SARA_R5_error_t parseSocketReadIndicationUDP(int socket, int length); + SARA_R5_error_t parseSocketListenIndication(int listeningSocket, IPAddress localIP, unsigned int listeningPort, int socket, IPAddress remoteIP, unsigned int port); + SARA_R5_error_t parseSocketCloseIndication(String *closeIndication); + + // UART Functions + size_t hwPrint(const char *s); + size_t hwWriteData(const char *buff, int len); + size_t hwWrite(const char c); + int readAvailable(char *inString); + char readChar(void); + int hwAvailable(void); + void beginSerial(unsigned long baud); + void setTimeout(unsigned long timeout); + bool find(char *target); + + SARA_R5_error_t autobaud(unsigned long desiredBaud); + + char *sara_r5_calloc_char(size_t num); + + bool processURCEvent(const char *event); + void pruneBacklog(void); + + // GPS Helper functions + char *readDataUntil(char *destination, unsigned int destSize, char *source, char delimiter); + bool parseGPRMCString(char *rmcString, PositionData *pos, ClockData *clk, SpeedData *spd); }; #endif //SPARKFUN_SARA_R5_ARDUINO_LIBRARY_H