I have a Photon 2 connected to a NEO-6MV2 and it works fine except for the precision limitations of the GPS module. I was under the (apparently wrong) impression that the NEO-M8N was a direct replacement for the NEO-6MV2 except for supply voltage being 3.3V rather than 5V. And yet, my code is not able to interpret the serial data that is being returned by the new GPS module. I have confirmed that it is returning data, but my code simply does not manage to read it. Is there some setting that I need to apply for the Particle-GPS library so that it knows that it needs to read from a M8N rather than a 6MV2?
Here is the (redacted) code I am using:
#include <Particle-GPS.h>
#include <neopixel.h>
SYSTEM_MODE(AUTOMATIC);
SYSTEM_THREAD(ENABLED);
const String DeviceID = "XXXXXX"; //registration number of vehicle on which the device will be installed
// IMPORTANT: Set pixel COUNT, PIN and TYPE
#define PIXEL_PIN SPI1 //for Particle Photon 2/P2
#define PIXEL_COUNT 1
#define PIXEL_TYPE WS2812
// *** Create a Gps instance. The RX an TX pins are connected to
// *** the TX and RX pins on the electron (Serial1).
Gps _gps = Gps(&Serial1);
// *** Create a timer that fires every 1 ms to capture
// *** incoming serial port data from the GPS.
Timer _timer = Timer(1, onSerialData);
const unsigned long NoFixGracePeriod = 900000; //15 minutes
unsigned long lastResetTime = 0;
unsigned long LastAlertUpload = 0;
Adafruit_NeoPixel strip(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
void setup()
{
// *** Initialize the USB Serial for debugging.
Serial.begin();
Serial.println("Initializing...");
// *** Initialize the GPS.
_gps.begin(9600);
// *** Start the timer.
_timer.start();
// WS2812 //
strip.begin();
strip.show();
strip.setPixelColor(0, strip.Color(255, 255, 0)); //yellow
strip.show();
////////////
lastResetTime = millis();
delay(2000);
}
void onSerialData()
{
_gps.onSerialData();
}
void loop()
{
double latitude = 0;
double longitude = 0;
int satellites;
double speed;
double altitude;
double bearing;
if(isPhotonConnectedToWiFi()){
// *** Get the Antenna Status ($PGTOP). //
Pgtop pgtop = Pgtop(_gps);
if (pgtop.parse())
{
Serial.println("1) Antenna Status ($PGTOP)");
Serial.println("======================================================");
Serial.print("Command ID: "); Serial.println(pgtop.commandId);
Serial.print("Antenna Status: "); Serial.println(pgtop.reference);
Serial.println("");
}
//////////////////////////////////////////
// *** Get the Global Positioning System Fixed Data ($GPGGA).
Gga gga = Gga(_gps);
if (gga.parse())
{
Serial.print("UTC Time: "); Serial.println(gga.utcTime);
char latHemisphere = 'N';
latitude = convertGGAToDecimal(gga.latitude, latHemisphere);
Serial.print("Latitude: "); Serial.println(gga.latitude + "(" + latitude + ")");
char lonHemisphere = 'E';
longitude = convertGGAToDecimal(gga.longitude, lonHemisphere);
Serial.print("Longitude: "); Serial.println(gga.longitude + "(" + longitude + ")");
Serial.print("Position Fix Indicator: "); Serial.println(gga.positionFixIndicator);
Serial.print("Satellites Used: "); Serial.println(gga.satellitesUsed);
satellites = gga.satellitesUsed;
Serial.print("Altitude: "); Serial.print(gga.altitude); Serial.print(" "); Serial.println(gga.altitudeUnit);
altitude = gga.altitude;
strip.setPixelColor(0, strip.Color(255, 255, 0)); //yellow
strip.show();
}
// *** Get the Recommended Minimum Navigation Information ($GPRMC).
Rmc rmc = Rmc(_gps);
if (rmc.parse())
{
if((latitude==0)||(longitude==0)){
latitude = atof(rmc.latitude.c_str());
longitude = atof(rmc.longitude.c_str());
}
Serial.print("Speed Over Ground: "); Serial.println(rmc.speedOverGround);
speed = rmc.speedOverGround;
Serial.print("Course Over Ground: "); Serial.println(rmc.courseOverGround);
bearing = rmc.courseOverGround;
Serial.print("Date: "); Serial.println(rmc.date);
Serial.print("Mode: "); Serial.println(rmc.mode);
Serial.println("");
strip.setPixelColor(0, strip.Color(0, 255, 0)); //green
strip.show();
}
}
else {
Serial.println("Not connected to WiFi");
strip.setPixelColor(0, strip.Color(255, 0, 0)); //red
strip.show();
}
delay(3000);
}
float convertGGAToDecimal(String ggaCoord, char hemisphere) {
int degrees;
float minutes;
float decimalDegrees;
//return ggaCoord.toFloat();
// Convert String to C-style string
char cstr[ggaCoord.length() + 1];
ggaCoord.toCharArray(cstr, ggaCoord.length() + 1);
// Determine if the coordinate is latitude or longitude based on string length
int coordLen = strlen(cstr);
if ((hemisphere == 'E')||(hemisphere == 'W')) {
// Longitude
degrees = (cstr[0] - '0') * 100 + (cstr[1] - '0') * 10 + (cstr[2] - '0');
minutes = atof(cstr + 3);
} else {
// Latitude
degrees = (cstr[0] - '0') * 10 + (cstr[1] - '0');
minutes = atof(cstr + 2);
}
// Convert minutes to decimal degrees
decimalDegrees = degrees + (minutes / 60.0);
// Apply the hemisphere factor
if (hemisphere == 'S' || hemisphere == 'W') {
decimalDegrees = -decimalDegrees;
}
return decimalDegrees;
}
bool isPhotonConnectedToWiFi() {
return WiFi.ready();
}