CAR_GPS_TRACKER/CAR_GPS_TRACKER.ino
2025-08-23 07:28:01 +10:00

275 lines
7.5 KiB
C++

#include <ArduinoJson.h>
#include <HardwareSerial.h>
// --- SIM7080G Pin Definitions ---
#define LTE_RX_PIN 16 // ESP32 GPIO16 connected to SIM7080G TX
#define LTE_TX_PIN 17 // ESP32 GPIO17 connected to SIM7080G RX
#define PWRKEY_PIN 4 // ESP32 GPIO4 connected to SIM7080G PWRKEY
// --- Network Configuration ---
const char *HOLOGRAM_APN = "hologram";
// --- Global Variables ---
String currentIMEI = "";
// --- Function Prototypes ---
void powerOnModule();
void powerOffModule();
String sendATCommand(String command, unsigned long timeoutMs = 3000);
String getIMEI();
bool activatePDPContextAndBearer();
void getGpsLocation(); // Function to get and print GPS data
void setup() {
Serial.begin(115200);
while (!Serial) {
delay(10);
}
Serial.println("--- Starting ESP32 to SIM7080G GPS Test (Final) ---");
Serial2.begin(115200, SERIAL_8N1, LTE_RX_PIN, LTE_TX_PIN);
powerOffModule();
delay(3000);
powerOnModule();
// Step 1: "Nudge and Listen" for the initial boot-up.
Serial.println(
"Waiting for initial module boot (90s timeout)...");
unsigned long startTime = millis();
unsigned long lastNudgeTime = 0;
const unsigned long NUDGE_INTERVAL = 3000;
bool moduleBooted = false;
String bootResponse = "";
while (millis() - startTime < 90000 && !moduleBooted) {
while (Serial2.available()) {
char c = Serial2.read();
Serial.write(c);
bootResponse += c;
if (bootResponse.indexOf("SMS Ready") != -1) {
moduleBooted = true;
break;
}
}
if (moduleBooted) {
break;
}
if (millis() - lastNudgeTime > NUDGE_INTERVAL) {
Serial2.println("AT");
lastNudgeTime = millis();
}
}
if (!moduleBooted) {
Serial.println("Module did not complete initial boot. Halting.");
while (true)
;
}
Serial.println("\nInitial boot successful!");
// Step 2: Apply the proven network configuration from your manual test.
Serial.println("\nApplying network configuration...");
sendATCommand("AT+CMEE=1", 1000);
sendATCommand("AT+CNMP=38", 5000);
sendATCommand("AT+CMNB=3", 5000);
// Step 3: Perform the full CFUN reset cycle to apply settings.
Serial.println("Applying settings with full CFUN reset...");
sendATCommand("AT+CFUN=0", 5000);
delay(5000);
sendATCommand("AT+CFUN=1", 10000);
// Step 4: Wait for the modem to apply settings and find the network.
Serial.println(
"Waiting 45 seconds for modem to apply settings and find network...");
delay(45000);
Serial.println("\nChecking network status...");
currentIMEI = getIMEI();
// Step 5: Check for network registration.
unsigned long networkRegStartTime = millis();
bool networkRegistered = false;
while (millis() - networkRegStartTime < 120000 && !networkRegistered) {
String regResponse = sendATCommand("AT+CGREG?", 3000);
if (regResponse.indexOf("+CGREG: 0,1") != -1 ||
regResponse.indexOf("+CGREG: 0,5") != -1) {
networkRegistered = true;
}
if (networkRegistered) {
Serial.println("Network registration successful!");
break;
}
Serial.println("Not yet registered. Retrying...");
delay(5000);
}
if (!networkRegistered) {
Serial.println("Failed to register to network. Halting.");
while (true)
;
}
// --- GPS INITIALIZATION ---
Serial.println("\n--- Turning on GPS ---");
sendATCommand("AT+CGPS=1", 1000); // Turn on the GPS receiver
Serial.println(
"GPS is on. It may take several minutes to get the first fix.");
Serial.println("\n--- Setup complete. Starting main loop. ---");
}
void loop() {
Serial.println("\n--- Requesting GPS Location ---");
getGpsLocation();
delay(30000); // Wait 30 seconds before the next request
}
void getGpsLocation() {
String response = sendATCommand("AT+CGPSINFO", 5000);
if (response.indexOf("+CGPSINFO:") != -1) {
response.replace("+CGPSINFO: ", "");
response.trim();
if (response.startsWith(",")) {
Serial.println("GPS has no fix yet.");
return;
}
int firstComma = response.indexOf(',');
String latDDMM = response.substring(0, firstComma);
int secondComma = response.indexOf(',', firstComma + 1);
String nsIndicator = response.substring(firstComma + 1, secondComma);
int thirdComma = response.indexOf(',', secondComma + 1);
String lonDDMM = response.substring(secondComma + 1, thirdComma);
int fourthComma = response.indexOf(',', thirdComma + 1);
String ewIndicator = response.substring(thirdComma + 1, fourthComma);
double latitude = 0.0;
if (latDDMM.length() > 2) {
double degrees = latDDMM.substring(0, 2).toDouble();
double minutes = latDDMM.substring(2).toDouble();
latitude = degrees + (minutes / 60.0);
if (nsIndicator == "S") {
latitude = -latitude;
}
}
double longitude = 0.0;
if (lonDDMM.length() > 3) {
double degrees = lonDDMM.substring(0, 3).toDouble();
double minutes = lonDDMM.substring(3).toDouble();
longitude = degrees + (minutes / 60.0);
if (ewIndicator == "W") {
longitude = -longitude;
}
}
Serial.print("Latitude: ");
Serial.println(latitude, 6);
Serial.print("Longitude: ");
Serial.println(longitude, 6);
} else {
Serial.println("Failed to get GPS info from module.");
}
}
// --- All other helper functions remain the same ---
void powerOnModule() {
Serial.println("Executing SIM7080G power-on sequence...");
pinMode(PWRKEY_PIN, OUTPUT);
digitalWrite(PWRKEY_PIN, HIGH);
delay(100);
digitalWrite(PWRKEY_PIN, LOW);
delay(2000);
digitalWrite(PWRKEY_PIN, HIGH);
}
void powerOffModule() {
Serial.println("Executing SIM7080G power-off sequence...");
pinMode(PWRKEY_PIN, OUTPUT);
digitalWrite(PWRKEY_PIN, HIGH);
delay(100);
digitalWrite(PWRKEY_PIN, LOW);
delay(2000);
digitalWrite(PWRKEY_PIN, HIGH);
}
String sendATCommand(String command, unsigned long timeoutMs) {
Serial.print("Sending: ");
Serial.println(command);
while (Serial2.available()) {
Serial2.read();
}
Serial2.println(command);
String response = "";
unsigned long startTime = millis();
while (millis() - startTime < timeoutMs) {
while (Serial2.available()) {
char c = (char)Serial2.read();
response += c;
startTime = millis();
if (response.endsWith("OK\r\n") || response.endsWith("ERROR\r\n") ||
response.endsWith("FAIL\r\n")) {
response.trim();
return response;
}
}
}
response.trim();
return response;
}
String getIMEI() {
String response = sendATCommand("AT+CGSN", 5000);
int currentPos = 0;
while (currentPos < response.length()) {
int nextNewline = response.indexOf('\n', currentPos);
String line = (nextNewline == -1)
? response.substring(currentPos)
: response.substring(currentPos, nextNewline);
currentPos = (nextNewline == -1) ? response.length() : nextNewline + 1;
line.trim();
if (line.length() == 15) {
bool allDigits = true;
for (int i = 0; i < line.length(); i++) {
if (!isDigit(line.charAt(i))) {
allDigits = false;
break;
}
}
if (allDigits) {
return line;
}
}
}
return "";
}
// This function is no longer called in setup, but is kept for future use
bool activatePDPContextAndBearer() {
Serial.println("Defining PDP Context...");
String response = sendATCommand(
"AT+CGDCONT=1,\"IP\",\"" + String(HOLOGRAM_APN) + "\"", 5000);
if (response.indexOf("OK") == -1)
return false;
Serial.println("Activating PDP Context...");
response = sendATCommand("AT+CGACT=1,1", 10000);
if (response.indexOf("OK") == -1)
return false;
Serial.println("Waiting 5 seconds for IP assignment...");
delay(5000);
Serial.println("Checking IP address...");
response = sendATCommand("AT+CGPADDR=1", 5000);
if (response.indexOf("+CGPADDR: 1,") == -1)
return false;
return true;
}