Closed theincredibleschnigges closed 6 years ago
As mentioned here, to take the "parsed" NMEA values from a comma-separated response string, do something like this:
// After final CR/LF received in char array "receivedChars":
char *field = strtok( receivedChars, "," ); // first field is GPS run status
field = strtok( nullptr, "," ); // FIX status
field = strtok( nullptr, "," ); // UTC date/time
field = strtok( nullptr, "," ); // Lat
float lat =atof( field );
field = strtok( nullptr, "," ); // Lon
float lon = atof( field );
field = strtok( nullptr, "," ); // Alt
float alt = atof( field );
field = strtok( nullptr, "," ); // Speed
field = strtok( nullptr, "," ); // Course
field = strtok( nullptr, "," ); // Fix Mode (0 = none, 1 = standard, 2 = differential)
int fixMode = atoi( field );
field = strtok( nullptr, "," ); // Reserved
field = strtok( nullptr, "," ); // HDOP
float hdop = atof( field );
field = strtok( nullptr, "," ); // PDOP
field = strtok( nullptr, "," ); // VDOP
field = strtok( nullptr, "," ); // Reserved
field = strtok( nullptr, "," ); // GPS satellites in view
field = strtok( nullptr, "," ); // GNSS satellites in view
int satellites = atoi( field );
Serial.print( fixMode );
Serial.print( ',' );
Serial.print( hdop );
Serial.print( ',' );
Serial.print( satellites );
Serial.print( ',' );
if ((fixMode >= 1) && (hdop <= 2.0) && (satellites >= 4)) {
// lat and lon are probably ok...
Serial.print( lat );
Serial.print( ',' );
Serial.print( lon );
}
Serial.println();
Different devices have different field orders, so check them carefully.
To process the raw NMEA characters from the SIM800 stream (after putting it in that mode), you can do something like this:
switch (state) {
case WAITING:
serialClear();
if (millis() - stateTime >= 10000) // once every 10 seconds
state = GPS_PWR_ON;
break;
case GPS_PWR_ON:
//DEBUG("GPS PWR ON");
SIMCOM.println( F("AT+CGPSPWR=1") );
state = GPS_PWR_ON_DELAY;
stateTime = millis();
break;
case GPS_PWR_ON_DELAY:
serialClear();
if (millis() - stateTime >= 200)
state = GPS_PKT_ON;
break;
case GPS_PKT_ON:
//DEBUG("GPS PKT ON");
SIMCOM.println( F("AT+CGPSOUT=1") );
state = GPS_PKT_ON_DELAY;
stateTime = millis();
break;
case GPS_PKT_ON_DELAY:
serialClear();
if (millis() - stateTime >= 200)
state = GET_GPS;
break;
case GET_GPS:
if (gps.available( SIMCOM )) {
fix = gps.read(); // received an RMC!
//DEBUG("OUT OF BOX");
// You might want to make sure there is valid data from the GPS.
// It may have bad reception, so you need to decide what to do when
// there is no valid data.
// You could stay in this state until the fix becomes valid,
// and then send the message. Your program could get stuck here
// if the GPS antenna is broken. Maybe that's what it should do.
// Or you could go ahead and send a message without a lat/lon,
// and hope that the TEMP alarm will trigger multiple times.
// With the if test commented out, it will send a message now,
// without a lat/lon value.
//if (fix.valid.date && fix.valid.time && fix.valid.location) {
// What to do with the GPS data?
Serial.print( fix.dateTime.seconds );
Serial.print( ' ' );
Serial.println( fix.latitude(), 6 );
state = GET_GPS_DELAY;
stateTime = millis();
//} else {
// ???
//}
}
break;
This assumes that you have implemented a state machine to track the different modes of the SIM800 device. And this code does not show all the commands that you may need to send. Seems like I saw a AT+CGPSRD=1 command that was also needed.
IIRC, you can also make the SIM device "forward" the GPS data to a different set of GPS_RX and GPS_TX pins. Simply connect those to your Arduino and read from those pins using a different gpsPort
variable (separate from the SIM serial object). Issue #68 also mentions putting the modem in "Test Mode" to receive the GPS data.
@theincredibleschnigges please try this piece of code
Thank you very much for the very detailed answer! I will take a look at it.
I am working with a SIM808 module which combines GSM and GPS processing. Retrieving data from the module works by sending an AT command and awaiting the response. There is no continuous stream of data over the serial port.
Is there a method that takes e.g. a char* containing a parsed NMEA message (see https://www.elecrow.com/download/SIM800%20Series_GNSS_Application%20Note%20V1.00.pdf page 10) instead of reading from serial port using available(...)?
I just saw that I apparently can also configure the module the send the GPS data over the serial port using AT+CGNSTST (see beginning of page 8 of the pdf) - but I have no idea how that interferes with the GSM communication - and neither does the library I am using (TinyGSM) support that :(
I would appreciate it very much if anyone had an idea how to make this setup (SIM808/TinyGSM with NeoGPS) work.