diff --git a/.github/workflows/arduino-lint.yml b/.github/workflows/arduino-lint.yml index e280129..87c995e 100644 --- a/.github/workflows/arduino-lint.yml +++ b/.github/workflows/arduino-lint.yml @@ -22,7 +22,7 @@ jobs: uses: arduino/arduino-lint-action@v1 with: compliance: specification - library-manager: submit + library-manager: update # Always use this setting for official repositories. Remove for 3rd party projects. official: true project-type: library \ No newline at end of file diff --git a/README.md b/README.md index 1bf33c6..e9f0f75 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Arduino Cellular +# 📡 Arduino Cellular [![Arduino Lint](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/arduino-lint.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/arduino-lint.yml) [![Compile Examples](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/compile-examples.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/compile-examples.yml) [![Spell Check](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/spell-check.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/spell-check.yml) [![Sync Labels](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/sync-labels.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/sync-labels.yml) [![Render Documentation](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/render-documentation.yml/badge.svg)](https://github.com/arduino-libraries/Arduino_Cellular/actions/workflows/render-documentation.yml) @@ -6,20 +6,23 @@ This library provides a toolkit for interacting with the official Arduino 4G Modules. It allows you to connect to the internet, send and receive SMS messages, and get location from the cellular network or GPS. ## Examples -* [examples/HTTPClient]() - Example of using this library together with [HttpClient]() to connect to a web server -* [examples/HTTPClient]() - Example of using this library together with [HttpClient]() that uses [BearSSL]() under the hood to create a secure connection to a web server -* [examples/ReceiveSMS]() - Example for the SMS sending and receiving functionality -* [examples/TimeAndLocation]() - Use GPS, or Cellular to acquire the location and time of the device. -* [examples/ModemTerminal]() - A handy example for debugging and Testing AT commands - -## Features +* [DeleteSMS](examples/DeleteSMS) - Example that shows how to delete SMS. +* [GetLocation](examples/GetLocation) - Shows how to get the current GPS location. +* [GetTime](examples/GetTime) - Use GPS to acquire the time of the device. +* [HTTPClient](examples/HTTPClient) - Example of using this library together with [ArduinoHttpClient]() to connect to a web server +* [HTTPSClient](examples/HTTPSClient) - Example of using this library together with [ArduinoHttpClient]() that uses [BearSSL]() under the hood to create a secure connection to a web server +* [ModemTerminal](examples/ModemTerminal) - A handy example for debugging and Testing AT commands +* [ReceiveSMS](examples/ReceiveSMS) - Example for the SMS sending and receiving functionality +* [SendSMS](examples/SendSMS) - Shows how to send an SMS + +## ✨ Features * Fast 4G connection to the internet * Secure SSL connections with BearSSL * Get location using GPS or GSM * Synchronise time with the cell provider * Send and Receive SMS Messages -## Instructions +## 👀 Instructions 1. Insert your Arduino 4G module to the Arduino Portenta Mid Carrier 2. Insert a valid SIM card either on the back of the Arduino 4G miniPCI board, or the **PCIE_SIM** connector on the Portenta Mid Carrier 3. Connect the 6 **SERIAL1** header pins to their corresponding pins on the **PCIE_BREAKOUT** header using jumpers @@ -27,8 +30,8 @@ This library provides a toolkit for interacting with the official Arduino 4G Mod 4. Connect the **3V3 PCIE** pin to the **3V3 Buck** ![](https://raw.githubusercontent.com/arduino-libraries/Arduino_Cellular/main/extras/connection_img/buck.jpg?token=GHSAT0AAAAAACNPRJPUBUCALG2FUCDZ7AVCZQVDLJA) 5. Connect external power to the Mid Carrier, via the **VIN** (5-12V) because modem use a lot of power when connecting or getting a GPS location. Make sure your supply can handle around 3A. -6. Get the APN settings from your network operator and add them to the "ArduinoSecrets.h" file for each sketch -```c +6. Get the APN settings from your network operator and add them to the "arduino_secrets.h" file for each sketch +```cpp const char apn[] = "live.vodafone.com"; const char gprsUser[] = "live"; const char gprsPass[] = ""; @@ -36,4 +39,6 @@ const char gprsPass[] = ""; 7. Install the library and it's dependencies 8. Enjoy +## 📖 Documentation +For more information about this library please read the documentation [here](./docs). \ No newline at end of file diff --git a/examples/DeleteSMS/DeleteSMS.ino b/examples/DeleteSMS/DeleteSMS.ino new file mode 100644 index 0000000..966a763 --- /dev/null +++ b/examples/DeleteSMS/DeleteSMS.ino @@ -0,0 +1,63 @@ +/** + * This example demonstrates how to delete SMS messages using the ArduinoCellular library. + * + * Instructions: + * 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * with a current rating of at least 2A and connect it to the VIN and GND pins. + * 3. Send an SMS to the SIM card number to test the SMS reception. + * 4. Upload the sketch to the connected Arduino board. + * 5. Check the serial monitor for the received SMS. + * 6. Enter the index of the SMS you want to delete in the serial monitor. + * + * Initial author: Sebastian Romero +*/ + +#include "ArduinoCellular.h" + +ArduinoCellular cellular = ArduinoCellular(); + +void printMessages(std::vector msg){ + for(int i = 0; i < msg.size(); i++){ + Serial.println("SMS:"); + Serial.print("* Index: "); Serial.println(msg[i].index); + Serial.print("* From: "); Serial.println(msg[i].sender); + Serial.print("* Timestamp: "); Serial.println(msg[i].timestamp.getISO8601()); + Serial.println("* Message: "); Serial.println(msg[i].message); + Serial.println("--------------------\n"); + } +} + +void setup(){ + Serial.begin(115200); + while (!Serial); + cellular.begin(); + delay(2000); // Give the modem some time to initialize +} + +void loop(){ + std::vector readSMS = cellular.getReadSMS(); + if(readSMS.size() > 0){ + Serial.println("Read SMS:"); + printMessages(readSMS); + } + + std::vector unreadSMS = cellular.getUnreadSMS(); + if(unreadSMS.size() > 0){ + Serial.println("Unread SMS:"); + printMessages(unreadSMS); + } + + // Prompt user which SMS to delete + Serial.println("Enter the index of the SMS you want to delete:"); + + while(Serial.available() == 0); + auto index = Serial.readStringUntil('\n').toInt(); + Serial.println("Deleting SMS..."); + + if(cellular.deleteSMS(index)){ + Serial.println("SMS deleted."); + } else { + Serial.println("Failed to delete SMS."); + } +} diff --git a/examples/GetLocation/GetLocation.ino b/examples/GetLocation/GetLocation.ino new file mode 100644 index 0000000..7ec02a7 --- /dev/null +++ b/examples/GetLocation/GetLocation.ino @@ -0,0 +1,37 @@ +/** + * This example demonstrates how to get the current GPS location using the ArduinoCellular library. + * + * Instructions: + * 1. Move the Arduino Pro 4G Module to an outdoor location with a clear view of the sky. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * 3. Upload the sketch to the connected Arduino board. + * 4. Open the serial monitor to view the output. + * + * Initial author: Sebastian Romero +*/ + +#include "ArduinoCellular.h" + +ArduinoCellular cellular = ArduinoCellular(); + +void setup(){ + Serial.begin(115200); + while (!Serial); + cellular.setDebugStream(Serial); + cellular.begin(); + + if(!cellular.enableGPS()){ + Serial.println("Failed to enable GPS"); + while(true); // Stop the program + } + delay(2000); // Give the modem some time to initialize +} + +void loop(){ + Location location = cellular.getGPSLocation(); + Serial.println("GPS Location:"); + Serial.print("* Latitude: "); Serial.println(location.latitude, 6); + Serial.print("* Longitude: "); Serial.println(location.longitude, 6); + Serial.println("--------------------\n"); + delay(10000); +} diff --git a/examples/GetTime/GetTime.ino b/examples/GetTime/GetTime.ino new file mode 100644 index 0000000..af4e2b4 --- /dev/null +++ b/examples/GetTime/GetTime.ino @@ -0,0 +1,41 @@ +/** + * This example demonstrates how to get the current time using the ArduinoCellular library. + * It derives the time from GPS connection. + * + * Instructions: + * 1. Move the Arduino Pro 4G Module to an outdoor location with a clear view of the sky. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * 3. Upload the sketch to the connected Arduino board. + * 4. Open the serial monitor to view the output. + * + * Initial author: Cristian Dragomir +*/ + +#include "ArduinoCellular.h" + +ArduinoCellular cellular = ArduinoCellular(); + +void setup(){ + Serial.begin(115200); + while (!Serial); + cellular.begin(); + + if(!cellular.enableGPS()){ + Serial.println("Failed to enable GPS"); + while(true); // Stop the program + } + delay(2000); // Give the modem some time to initialize +} + +void loop(){ + Location location = cellular.getGPSLocation(10000); + + if(location.latitude == 0.0 && location.longitude == 0.0){ + Serial.println("Failed to get GPS location"); + } else { + Time time = cellular.getGPSTime(); + Serial.print("Current time (ISO8601): "); Serial.println(time.getISO8601()); + } + + delay(10000); +} \ No newline at end of file diff --git a/examples/HTTPClient/HTTPClient.ino b/examples/HTTPClient/HTTPClient.ino index 5525676..fa275ce 100644 --- a/examples/HTTPClient/HTTPClient.ino +++ b/examples/HTTPClient/HTTPClient.ino @@ -1,3 +1,18 @@ +/** + * This example demonstrates how to make a HTTP GET request using + * the ArduinoHttpClient library and the ArduinoCellular library. + * + * Instructions: + * 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * with a current rating of at least 2A and connect it to the VIN and GND pins. + * 3. Specify the APN, login, and password for your cellular network provider. + * 4. Upload the sketch to the connected Arduino board. + * 5. Open the serial monitor to view the output. + * + * Initial author: Cristian Dragomir +*/ + #define ARDUINO_CELLULAR_DEBUG #include "ArduinoCellular.h" @@ -10,14 +25,7 @@ const int port = 80; ArduinoCellular cellular = ArduinoCellular(); HttpClient client = cellular.getHTTPClient(server, port); -void setup(){ - Serial.begin(115200); - while (!Serial); - cellular.begin(); - cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD, SECRET_PINNUMBER); -} - -void loop(){ +void getResource(){ Serial.println("Making GET request..."); @@ -32,7 +40,27 @@ void loop(){ Serial.println(response); client.stop(); +} - delay(5000); +void setup(){ + Serial.begin(115200); + while (!Serial); + // cellular.setDebugStream(Serial); // Uncomment this line to enable debug output + cellular.begin(); + if(String(SECRET_PINNUMBER).length() > 0 && !cellular.unlockSIM(SECRET_PINNUMBER)){ + Serial.println("Failed to unlock SIM card."); + while(true); // Stop here + } + + Serial.println("Connecting..."); + if(!cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD)){ + Serial.println("Failed to connect to the network."); + while(true); // Stop here + } + Serial.println("Connected!"); + + getResource(); } + +void loop(){} diff --git a/examples/HTTPSClient/HTTPSClient.ino b/examples/HTTPSClient/HTTPSClient.ino index f4b45d7..20a328a 100644 --- a/examples/HTTPSClient/HTTPSClient.ino +++ b/examples/HTTPSClient/HTTPSClient.ino @@ -1,3 +1,17 @@ +/** + * Example demonstrating how to make an HTTPS GET request using + * the ArduinoHttpClient library and the ArduinoCellular library. + * + * Instructions: + * 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * with a current rating of at least 2A and connect it to the VIN and GND pins. + * 3. Specify the APN, login, and password for your cellular network provider. + * 4. Upload the sketch to the connected Arduino board. + * 5. Open the serial monitor to view the output. + * + * Initial author: Cristian Dragomir +*/ #include #include "ArduinoCellular.h" @@ -11,15 +25,7 @@ const int port = 443; ArduinoCellular cellular = ArduinoCellular(); HttpClient client = cellular.getHTTPSClient(server, port); -void setup(){ - Serial.begin(115200); - while (!Serial); - - cellular.begin(); - cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD, SECRET_PINNUMBER); -} - -void loop(){ +void getResource(){ Serial.println("Making GET request..."); client.get(resource); @@ -33,5 +39,28 @@ void loop(){ Serial.println(response); client.stop(); - delay(5000); } + +void setup(){ + Serial.begin(115200); + while (!Serial); + + // cellular.setDebugStream(Serial); // Uncomment this line to enable debug output + cellular.begin(); + + if(String(SECRET_PINNUMBER).length() > 0 && !cellular.unlockSIM(SECRET_PINNUMBER)){ + Serial.println("Failed to unlock SIM card."); + while(true); // Stop here + } + + Serial.println("Connecting..."); + if(!cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD)){ + Serial.println("Failed to connect to the network."); + while(true); // Stop here + } + Serial.println("Connected!"); + + getResource(); +} + +void loop(){} diff --git a/examples/ModemTerminal/ModemTerminal.ino b/examples/ModemTerminal/ModemTerminal.ino index 7436d2e..6d064ae 100644 --- a/examples/ModemTerminal/ModemTerminal.ino +++ b/examples/ModemTerminal/ModemTerminal.ino @@ -1,31 +1,46 @@ +/** + * The ModemTerminal example demonstrates how to use the ArduinoCellular library to send raw AT commands to the modem. + * + * Instructions: + * 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * with a current rating of at least 2A and connect it to the VIN and GND pins. + * 3. Specify the APN, login, and password for your cellular network provider. + * 4. Upload the sketch to the connected Arduino board. + * 5. Open the serial monitor and type AT commands to interact with the modem. + * + * Initial author: Cristian Dragomir +*/ + #include "ArduinoCellular.h" #include "arduino_secrets.h" - ArduinoCellular cellular = ArduinoCellular(); -float lat = 0.00; -float lon = 0.00; - - void setup(){ Serial.begin(115200); while (!Serial); + cellular.setDebugStream(Serial); // Uncomment this line to enable debug output cellular.begin(); - cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD, SECRET_PINNUMBER); + + if(String(SECRET_PINNUMBER).length() > 0 && !cellular.unlockSIM(SECRET_PINNUMBER)){ + Serial.println("Failed to unlock SIM card."); + while(true); // Stop here + } + + Serial.println("Connecting..."); + cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD); + Serial.println("Connected!"); + Serial.println("You can now send AT commands to the modem."); } void loop() { - if (Serial.available() > 0) { - // Define a buffer to store incoming data. Adjust the size as needed. - char incomingData[255]; // Adjust the size according to your needs - - // Read data from serial until newline is found - int size = Serial.readBytesUntil('\n', incomingData, sizeof(incomingData) - 1); // Leave space for null terminator - - // Null-terminate the string - incomingData[size] = '\0'; - // Call the sendATCommand function with the read data - Serial.println(cellular.sendATCommand(GF(incomingData))); - } + while(Serial.available() == 0); // Wait for user input + + // Read data from serial until newline + String userInput = Serial.readStringUntil('\n'); + + // Call the sendATCommand function with the read data + String response = cellular.sendATCommand(userInput.c_str()); + Serial.println(response); } \ No newline at end of file diff --git a/examples/ReceiveSMS/ReceiveSMS.ino b/examples/ReceiveSMS/ReceiveSMS.ino index 6564db4..c15351f 100644 --- a/examples/ReceiveSMS/ReceiveSMS.ino +++ b/examples/ReceiveSMS/ReceiveSMS.ino @@ -1,53 +1,89 @@ -#include "ArduinoCellular.h" -#include "arduino_secrets.h" +/** + * This example demonstrates how to receive SMS messages using ArduinoCellular library. + * It supports both polling and interrupt based methods to check for new SMS messages. + * + * Instructions: + * 1. Insert a SIM card with or without PIN code in the Arduino Pro 4G Module. + * 2. Provide sufficient power to the Arduino Pro 4G Module. Ideally, use a 5V power supply + * with a current rating of at least 2A and connect it to the VIN and GND pins. + * 3. Specify the PIN code of your SIM card if it has one. + * 4. Upload the sketch to the connected Arduino board. + * 5. Send an SMS to the SIM card number to test the SMS reception. + * 6. Check the serial monitor for the received SMS. + * + * Initial author: Cristian Dragomir +*/ -// #define TINY_GSM_DEBUG Serial -// #define ARDUINO_CELLULAR_DEBUG +#include "ArduinoCellular.h" constexpr int NEW_SMS_INTERRUPT_PIN = A0; ArduinoCellular cellular = ArduinoCellular(); volatile boolean smsReceived = false; +constexpr int POLLING_INTERVAL_MS = 1 * 60 * 1000; // 1 minute void printMessages(std::vector msg){ for(int i = 0; i < msg.size(); i++){ Serial.println("SMS:"); - Serial.print("\t * From: "); Serial.println(msg[i].number); - Serial.print("\t * Message: "); Serial.println(msg[i].message); - Serial.print("\t * Timestamp: "); Serial.println(msg[i].timestamp.getISO8601()); + Serial.print("* Index: "); Serial.println(msg[i].index); + Serial.print("* From: "); Serial.println(msg[i].sender); + Serial.print("* Timestamp: "); Serial.println(msg[i].timestamp.getISO8601()); + Serial.println("* Message: "); Serial.println(msg[i].message); + Serial.println("--------------------\n"); } } void onSMSReceived(){ - Serial.println("New SMS received!"); smsReceived = true; } void setup(){ Serial.begin(115200); while (!Serial); - cellular.setDebugStream(Serial); - + // cellular.setDebugStream(Serial); // Uncomment this line to enable debug output cellular.begin(); - Serial.println("Connecting..."); - cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD, SECRET_PINNUMBER); + + String pinCode = ""; // If your SIM card has a PIN code, specify it here e.g. "1234" + if(pinCode.length() > 0 && !cellular.unlockSIM(pinCode)){ + Serial.println("Failed to unlock SIM card."); + while(true); // Stop here + } + Serial.println("Connecting to network..."); + cellular.connect(); + Serial.println("Connected!"); + // Register interrupt based callback for new SMS attachInterrupt(digitalPinToInterrupt(NEW_SMS_INTERRUPT_PIN), onSMSReceived, RISING); - Serial.println("Read SMS:"); std::vector readSMS = cellular.getReadSMS(); - printMessages(readSMS); + if(readSMS.size() > 0){ + Serial.println("Read SMS:"); + printMessages(readSMS); + } - Serial.println("Unread SMS:"); std::vector unreadSMS = cellular.getUnreadSMS(); - printMessages(unreadSMS); + if(unreadSMS.size() > 0){ + Serial.println("Unread SMS:"); + printMessages(unreadSMS); + } } void loop(){ - if(smsReceived){ + static unsigned long lastPoll = 0; + static bool checkForNewSMS = false; + + if(millis() - lastPoll > POLLING_INTERVAL_MS){ + checkForNewSMS = true; + lastPoll = millis(); + } + + if(smsReceived || checkForNewSMS){ smsReceived = false; + checkForNewSMS = false; std::vector unreadSMS = cellular.getUnreadSMS(); + if (unreadSMS.size() > 0){ + Serial.println("New SMS received!"); printMessages(unreadSMS); } } diff --git a/examples/ReceiveSMS/arduino_secrets.h b/examples/ReceiveSMS/arduino_secrets.h deleted file mode 100644 index bbcdcc9..0000000 --- a/examples/ReceiveSMS/arduino_secrets.h +++ /dev/null @@ -1,10 +0,0 @@ -#define SECRET_PINNUMBER "" // replace with your SIM card PIN -#define SECRET_GPRS_APN "apn" // replace with your GPRS APN -#define SECRET_GPRS_LOGIN "login" // replace with your GPRS login -#define SECRET_GPRS_PASSWORD "password" // replace with your GPRS password - - -#define SECRET_PINNUMBER "1234" // replace with your SIM card PIN -#define SECRET_GPRS_APN "live.vodafone.com" // replace with your GPRS APN -#define SECRET_GPRS_LOGIN "live" // replace with your GPRS login -#define SECRET_GPRS_PASSWORD "" // replace with your GPRS password diff --git a/examples/SendSMS/SendSMS.ino b/examples/SendSMS/SendSMS.ino index 563d5b8..f65bd9c 100644 --- a/examples/SendSMS/SendSMS.ino +++ b/examples/SendSMS/SendSMS.ino @@ -15,10 +15,6 @@ */ #include "ArduinoCellular.h" -const char apn[] = "internet"; -const char gprsUser[] = ""; -const char gprsPass[] = ""; - ArduinoCellular cellular = ArduinoCellular(); void setup(){ @@ -26,11 +22,18 @@ void setup(){ while (!Serial); delay(1000); // Give the serial monitor some time to start + // cellular.setDebugStream(Serial); // Uncomment this line to enable debug output cellular.begin(); - String pinCode = "1234"; // If your SIM card has a PIN code, specify it here + + String pinCode = ""; // If your SIM card has a PIN code, specify it here e.g. "1234" + if(pinCode.length() > 0 && !cellular.unlockSIM(pinCode)){ + Serial.println("Failed to unlock SIM card."); + while(true); // Stop here + } Serial.println("Connecting to network..."); - cellular.connect(apn, gprsUser, gprsPass, pinCode); + cellular.connect(); // APN settings are not required for sending SMS + Serial.println("Connected!"); Serial.println("Sending SMS..."); cellular.sendSMS("", "bleep bleep"); diff --git a/examples/TimeAndLocation/TimeAndLocation.ino b/examples/TimeAndLocation/TimeAndLocation.ino deleted file mode 100644 index 2e2c286..0000000 --- a/examples/TimeAndLocation/TimeAndLocation.ino +++ /dev/null @@ -1,36 +0,0 @@ -#define DUMP_AT_COMMANDS - -#include "ArduinoCellular.h" -#include "arduino_secrets.h" - -ArduinoCellular cellular = ArduinoCellular(); - -float lat = 0.00000; -float lon = 0.00000; -int year = 0; -int month = 0; -int day = 0; -int hour = 0; -int minute = 0; -int second = 0; - - -void setup(){ - Serial.begin(115200); - while (!Serial); - cellular.begin(); - //cellular.connect(SECRET_GPRS_APN, SECRET_GPRS_LOGIN, SECRET_GPRS_PASSWORD, SECRET_PINNUMBER); - //cellular.enableGPS(false); -} - -void loop(){ - Location loc = cellular.getGPSLocation(10000); - Serial.print("Latitude: "); Serial.println(lat); - Serial.print("Longitude: "); Serial.println(lon); - - Time t = cellular.getGPSTime(); - Serial.print("ISO String: "); Serial.println(t.getISO8601()); - - delay(1000); - -} \ No newline at end of file diff --git a/examples/TimeAndLocation/arduino_secrets.h b/examples/TimeAndLocation/arduino_secrets.h deleted file mode 100644 index de218ed..0000000 --- a/examples/TimeAndLocation/arduino_secrets.h +++ /dev/null @@ -1,4 +0,0 @@ -#define SECRET_PINNUMBER "" // replace with your SIM card PIN -#define SECRET_GPRS_APN "apn" // replace with your GPRS APN -#define SECRET_GPRS_LOGIN "login" // replace with your GPRS login -#define SECRET_GPRS_PASSWORD "password" // replace with your GPRS password \ No newline at end of file diff --git a/src/ArduinoCellular.cpp b/src/ArduinoCellular.cpp index ad709fc..776d6ce 100644 --- a/src/ArduinoCellular.cpp +++ b/src/ArduinoCellular.cpp @@ -14,15 +14,13 @@ ArduinoCellular::ArduinoCellular() { } void ArduinoCellular::begin() { - // set sim slot modem.init(); - String modemInfo = this ->sendATCommand("I"); if(modemInfo.indexOf("EC200A") > 0){ this->model = ModemModel::EC200; - } else if (modemInfo.indexOf("EG95") > 0){ - this->model = ModemModel::EG95; + } else if (modemInfo.indexOf("EG25") > 0){ + this->model = ModemModel::EG25; } else { this->model = ModemModel::Unsupported; } @@ -43,38 +41,55 @@ void ArduinoCellular::begin() { } -bool ArduinoCellular::connect(String apn, String gprsUser, String gprsPass, String pin){ +bool ArduinoCellular::connect(String apn, String username, String password){ SimStatus simStatus = getSimStatus(); - if(simStatus == SimStatus::SIM_LOCKED && pin.length() > 0){ - unlockSIM(pin.c_str()); + + if(simStatus == SimStatus::SIM_LOCKED){ + if(this->debugStream != nullptr){ + this->debugStream->println("SIM locked, cannot connect to network."); + } + + return false; } - simStatus = getSimStatus(); - if(simStatus == SimStatus::SIM_READY) { - if(awaitNetworkRegistration()){ - if(connectToGPRS(apn.c_str(), gprsUser.c_str(), gprsPass.c_str())){ - if(this->debugStream != nullptr){ - this->debugStream->println("Setting DNS..."); - } - - auto response = this->sendATCommand("+QIDNSCFG=1,\"8.8.8.8\",\"8.8.4.4\""); - - if(this->debugStream != nullptr){ - this->debugStream->println(response); - } - return true; - } + if(simStatus != SimStatus::SIM_READY) { + if(this->debugStream != nullptr){ + this->debugStream->println("SIM not ready, cannot connect to network."); + } + return false; + } + + if(!awaitNetworkRegistration()){ + return false; + } + + if(apn.length() == 0){ + if(this->debugStream != nullptr){ + this->debugStream->println("No APN specified, not connecting to GPRS"); + } + return true; + } + + if(connectToGPRS(apn.c_str(), username.c_str(), password.c_str())){ + auto response = this->sendATCommand("+QIDNSCFG=1,\"8.8.8.8\",\"8.8.4.4\""); + + if(response.indexOf("OK") != -1){ + return true; } else { + if(this->debugStream != nullptr){ + this->debugStream->println("Failed to set DNS."); + } return false; } + } - return false; + return false; } Location ArduinoCellular::getGPSLocation(unsigned long timeout){ - if (model == ModemModel::EG95){ + if (model == ModemModel::EG25){ float latitude = 0.00000; float longitude = 0.00000; unsigned long startTime = millis(); @@ -189,11 +204,11 @@ SimStatus ArduinoCellular::getSimStatus(){ } } -bool ArduinoCellular::unlockSIM(const char * pin){ +bool ArduinoCellular::unlockSIM(String pin){ if(this->debugStream != nullptr){ this->debugStream->println("Unlocking SIM..."); } - return modem.simUnlock(pin); + return modem.simUnlock(pin.c_str()); } bool ArduinoCellular::awaitNetworkRegistration(){ @@ -214,31 +229,33 @@ bool ArduinoCellular::enableGPS(bool assisted){ this->debugStream->println("Enabling GPS..."); } + String response; + if(assisted){ - sendATCommand("AT+QGPSCFG=\"agpsposmode\",33488767"); + response = sendATCommand("+QGPSCFG=\"agpsposmode\",33488767", 10000); } else { - sendATCommand("AT+QGPSCFG=\"agpsposmode\",8388608"); + // Sets the 23rd bit to 1 to enable standalone GPS + response = sendATCommand("+QGPSCFG=\"agpsposmode\",8388608", 10000); } - //modem.sendAT(GF("+UTIME=1,1")); - //modem.waitResponse(); - //modem.sendAT(GF("+UGPIOC=23,0,1")); - - //modem.waitResponse(); + if(response.indexOf("OK") == -1){ + if(this->debugStream != nullptr){ + this->debugStream->println("Failed to set GPS mode."); + this->debugStream->println("Response: " + response); + } + return false; + } return modem.enableGPS(); - //delay(10000); } -String ArduinoCellular::sendATCommand( char * command, unsigned long timeout){ - String resp; - modem.sendAT(const_cast(command)); - modem.waitResponse(timeout, resp); - return resp; +String ArduinoCellular::sendATCommand(const char * command, unsigned long timeout){ + String response; + modem.sendAT(command); + modem.waitResponse(timeout, response); + return response; } - - Time parseTimestamp(const String ×tampStr) { int hour, minute, second, day, month, year, offset; @@ -249,9 +266,9 @@ Time parseTimestamp(const String ×tampStr) { int firstSlashIndex = date.indexOf('/'); int secondSlashIndex = date.lastIndexOf('/'); - day = date.substring(0, firstSlashIndex).toInt(); + year = date.substring(0, firstSlashIndex).toInt() + 2000; month = date.substring(firstSlashIndex + 1, secondSlashIndex).toInt(); - year = date.substring(secondSlashIndex + 1).toInt() + 2000; + day = date.substring(secondSlashIndex + 1).toInt(); int firstColonIndex = time.indexOf(':'); int secondColonIndex = time.lastIndexOf(':'); @@ -263,6 +280,7 @@ Time parseTimestamp(const String ×tampStr) { return Time(year, month, day, hour, minute, second, offset); } + // Parses a single SMS entry from the data SMS parseSMSEntry(const String& entry, const String& message) { SMS sms; @@ -272,8 +290,12 @@ SMS parseSMSEntry(const String& entry, const String& message) { int fourthQuoteIndex = entry.indexOf('"', thirdQuoteIndex + 1); int commaIndexBeforeTimestamp = entry.lastIndexOf(',', entry.lastIndexOf(',') - 1); + String command = "+CMGL: "; + // Index is between "+CMGL: " and first "," symbol + sms.index = entry.substring(entry.indexOf(command) + command.length(), entry.indexOf(',')).toInt(); + // Extracting number and raw timestamp - sms.number = entry.substring(thirdQuoteIndex + 1, fourthQuoteIndex); + sms.sender = entry.substring(thirdQuoteIndex + 1, fourthQuoteIndex); String rawTimestamp = entry.substring(commaIndexBeforeTimestamp + 2, entry.indexOf('+', commaIndexBeforeTimestamp) + 3); // Parse the timestamp @@ -293,13 +315,11 @@ std::vector splitStringByLines(const String& input, char delimiter = '\n if (endIndex == -1) endIndex = input.length(); String line = input.substring(startIndex, endIndex); - if(line.length() > 0 && line != "\r" && line != "\n" && line != "\r\n"){ - // Remove trailing \r if it exists - if (line.endsWith("\r")) { - line.remove(line.length() - 1); - } - lines.push_back(line); + // Remove trailing \r if it exists + if (line.endsWith("\r")) { + line.remove(line.length() - 1); } + lines.push_back(line); startIndex = endIndex + 1; } return lines; @@ -309,19 +329,33 @@ std::vector splitStringByLines(const String& input, char delimiter = '\n std::vector parseSMSData(const String& data) { std::vector smsList = std::vector(); std::vector lines = splitStringByLines(data); - - // Remove last line if it's "OK" - if (lines.size() > 0 && lines[lines.size() - 1] == "OK") { - lines.pop_back(); + + // Remove first line if it's empty + if (lines.size() > 0 && lines[0] == "") { + lines.erase(lines.begin()); } - for(int i = 0; i < lines.size(); i += 2){ + // Remove last 2 lines if second to last line is "OK" + if (lines.size() >= 2 && lines.back() == "OK") { + lines.erase(lines.end() - 2, lines.end()); + } + + for(int i = 0; i < lines.size(); i ++){ if (lines[i].startsWith("+CMGL:")) { + String entry = lines[i]; String message = ""; - if(i + 1 < lines.size()){ - message = lines[i + 1]; + // Loop through the lines until the next +CMGL line and extract the message by concatenating the lines + for (int j = i + 1; j < lines.size(); j++) { + if (lines[j].startsWith("+CMGL:")) { + i = j - 1; + break; + } + message += lines[j] + "\n"; } - SMS sms = parseSMSEntry(lines[i], message); + // Remove the trailing newline character from the message + message.remove(message.length() - 1); + + SMS sms = parseSMSEntry(entry, message); smsList.push_back(sms); } } @@ -351,6 +385,12 @@ std::vector ArduinoCellular::getUnreadSMS(){ } } +bool ArduinoCellular::deleteSMS(uint16_t index){ + String command = "+CMGD=" + String(index); + String response = sendATCommand(const_cast(command.c_str())); + return response.indexOf("OK") != -1; +} + void ArduinoCellular::setDebugStream(Stream &stream){ this->debugStream = &stream; } diff --git a/src/ArduinoCellular.h b/src/ArduinoCellular.h index e6ab0a6..697fb7b 100644 --- a/src/ArduinoCellular.h +++ b/src/ArduinoCellular.h @@ -27,7 +27,7 @@ */ enum ModemModel { EC200, /**< Quectel EC200 modem. */ - EG95, /**< Quectel EG95 modem. */ + EG25, /**< Quectel EG25 modem. */ Unsupported /**< Unsupported modem model. */ }; @@ -36,7 +36,8 @@ enum ModemModel { */ class SMS { public: - String number; /**< The phone number associated with the SMS. */ + int16_t index; /**< The index of the SMS message. */ + String sender; /**< The phone number associated with the SMS. */ String message; /**< The content of the SMS message. */ Time timestamp; /**< The timestamp when the SMS was received. */ @@ -45,19 +46,21 @@ class SMS { * Initializes the number, message, and timestamp to empty values. */ SMS() { - this->number = ""; + this->index = -1; + this->sender = ""; this->message = ""; this->timestamp = Time(); } /** * Constructor for SMS. - * @param number The phone number associated with the SMS. + * @param index The index of the SMS message. + * @param sender The phone number associated with the sender of the SMS. * @param message The content of the SMS message. * @param timestamp The timestamp when the SMS was received. */ - SMS(String number, String message, Time timestamp) { - this->number = number; + SMS(int16_t index, String sender, String message, Time timestamp) { + this->sender = sender; this->message = message; this->timestamp = timestamp; } @@ -92,14 +95,21 @@ class ArduinoCellular { void begin(); /** - * @brief Connects to the network using the specified APN, GPRS username, and GPRS password. - * @param apn The Access Point Name. - * @param gprsUser The GPRS username. - * @param gprsPass The GPRS password. + * @brief Unlocks the SIM card using the specified PIN. * @param pin The SIM card PIN. + * @return True if the SIM card is unlocked, false otherwise. + */ + bool unlockSIM(String pin); + + /** + * @brief Registers with the cellular network and connects to the Internet + * if the APN, GPRS username, and GPRS password are provided. + * @param apn The Access Point Name. + * @param username The APN username. + * @param password The APN password. * @return True if the connection is successful, false otherwise. */ - bool connect(String apn, String gprsUser, String gprsPass, String pin = ""); + bool connect(String apn = "", String username = "", String password = ""); /** * @brief Checks if the modem is registered on the network. @@ -127,13 +137,6 @@ class ArduinoCellular { */ Location getGPSLocation(unsigned long timeout = 60000); - /** - * @brief Gets the cellular location. (Blocking call) - * @param timeout The timeout (In milliseconds) to wait for the cellular location. - * @return The cellular location. If the location is not retrieved, the latitude and longitude will be 0.0. - */ - Location getCellularLocation(unsigned long timeout = 10000); - /** * @brief Gets the current time from the network. * @return The current time. @@ -165,13 +168,21 @@ class ArduinoCellular { */ std::vector getUnreadSMS(); + /** + * @brief Deletes an SMS message at the specified index. + * + * @param index The index of the SMS message to delete. + * @return True if the SMS message was successfully deleted, false otherwise. + */ + bool deleteSMS(uint16_t index); + /** * @brief Sends an AT command to the modem and waits for a response, then returns the response. * @param command The AT command to send. - * @param timeout The timeout (In milliseconds) to wait for the response. + * @param timeout The timeout (In milliseconds) to wait for the response. Default is 1000ms. * @return The response from the modem. */ - String sendATCommand(char * command, unsigned long timeout = 1000); + String sendATCommand(const char * command, unsigned long timeout = 1000); /** @@ -233,13 +244,6 @@ class ArduinoCellular { */ SimStatus getSimStatus(); - /** - * @brief Unlocks the SIM card using the specified PIN. - * @param pin The SIM card PIN. - * @return True if the SIM card is unlocked, false otherwise. - */ - bool unlockSIM(const char * pin); - /** * @brief Waits for network registration. (Blocking call) * @return True if the network registration is successful, false otherwise. diff --git a/src/ModemInterface.cpp b/src/ModemInterface.cpp index c1b8048..4ac5a54 100644 --- a/src/ModemInterface.cpp +++ b/src/ModemInterface.cpp @@ -4,32 +4,29 @@ #include - #if defined(ARDUINO_PORTENTA_C33) + #define ON_PIN 32 // P708 (32) is the ON pin + // P602/P110/P603/P604 -> Serial1 UART Serial1_FC(UART1_TX_PIN, UART1_RX_PIN, 61, 62); #ifdef DUMP_AT_COMMANDS StreamDebugger debugger(Serial1_FC, Serial); - __attribute__ ((init_priority (101))) ModemInterface modem(debugger, 32); + __attribute__ ((init_priority (101))) ModemInterface modem(debugger, ON_PIN); #else - __attribute__ ((init_priority (101))) ModemInterface modem(Serial1_FC, 32); + __attribute__ ((init_priority (101))) ModemInterface modem(Serial1_FC, ON_PIN); #endif -// P708 (32) is the ON pin #elif defined(ARDUINO_PORTENTA_H7_M7) || defined(CORE_CM4) -#include "pinDefinitions.h" - + #include "pinDefinitions.h" + #define ON_PIN PG_3 // PG3 is the ON pin -// P602/P110/P603/P604 -> Serial1 + // P602/P110/P603/P604 -> Serial1 #ifdef DUMP_AT_COMMANDS StreamDebugger debugger(Serial1, Serial); - __attribute__ ((init_priority (101))) ModemInterface modem(debugger, PinNameToIndex(PG_3)); + __attribute__ ((init_priority (101))) ModemInterface modem(debugger, PinNameToIndex(ON_PIN)); #else - __attribute__ ((init_priority (101))) ModemInterface modem(Serial1, PinNameToIndex(PG_3)); + __attribute__ ((init_priority (101))) ModemInterface modem(Serial1, PinNameToIndex(ON_PIN)); #endif - - -// PG3 () is the ON pin #endif diff --git a/src/ModemInterface.h b/src/ModemInterface.h index c04f1f4..9da2ce7 100644 --- a/src/ModemInterface.h +++ b/src/ModemInterface.h @@ -26,9 +26,9 @@ class ModemInterface : public TinyGsmBG96 { /** * @brief Constructor for the ModemInterface class. * @param stream The stream object for communication with the modem. - * @param power_pin The pin number for controlling the power of the modem. + * @param powerPin The pin number for controlling the power of the modem. */ - explicit ModemInterface(Stream& stream, int power_pin) : TinyGsmBG96(stream),stream(&stream),power_pin(power_pin) { + explicit ModemInterface(Stream& stream, int powerPin) : TinyGsmBG96(stream),stream(&stream),powerPin(powerPin) { }; @@ -38,8 +38,8 @@ class ModemInterface : public TinyGsmBG96 { * @return True if initialization is successful, false otherwise. */ bool init(const char* pin = NULL) { - pinMode(power_pin, OUTPUT); - digitalWrite(power_pin, HIGH); + pinMode(powerPin, OUTPUT); + digitalWrite(powerPin, HIGH); delay(1000); #ifdef DUMP_AT_COMMANDS #if defined(ARDUINO_PORTENTA_C33) @@ -54,7 +54,7 @@ class ModemInterface : public TinyGsmBG96 { public: Stream* stream; /**< The stream object for communication with the modem. */ - int power_pin; /**< The pin number for controlling the power of the modem. */ + int powerPin; /**< The pin number for controlling the power of the modem. */ }; /**