New version of build() with more sentences

move addChecksum() to NMEA_build.cpp
This commit is contained in:
Rick Sellens 2020-01-29 10:03:59 -05:00
parent 0b0996bbb0
commit 4b6e181770
2 changed files with 416 additions and 42 deletions

View File

@ -159,27 +159,6 @@ bool Adafruit_GPS::isEmpty(char *pStart) {
return true;
}
/**************************************************************************/
/*!
@brief Add *CS where CS is the two character hex checksum for all but
the first character in the string. The checksum is the result of an
exclusive or of all the characters in the string. Also useful if you
are creating new PMTK strings for controlling a GPS module and need a
checksum added.
@param buff Pointer to the string, which must be long enough
@return none
*/
/**************************************************************************/
void Adafruit_GPS::addChecksum(char *buff) {
char cs = 0;
int i = 1;
while (buff[i]) {
cs ^= buff[i];
i++;
}
sprintf(buff, "%s*%02X", buff, cs);
}
/**************************************************************************/
/*!
@brief Parse a part of an NMEA string for time

View File

@ -45,10 +45,16 @@
build() will not work properly in an environment that does not support
the %f floating point formatter in sprintf(), and will return NULL.
Floating point arguments to sprintf() are explicitly cast to double to
avoid warnings in some compilers.
build() adds Carriage Return and Line Feed to sentences to conform to
NMEA-183, so send your output with a print, not a println.
The resulting sentence may be corrupted if the input data is corrupt.
In particular, the sentence will be truncated if any of the character
data is 0, e.g. if lat is not set to 'N' or 'S'.
Some of the data in these test sentences may be arbitrary, e.g. for the
TXT sentence which has a more complicated protocol for multiple lines
sent as a message set. Also, the data in the class variables are presumed
@ -66,7 +72,7 @@
/**************************************************************************/
char *Adafruit_GPS::build(char *nmea, const char *thisSource,
const char *thisSentence, char ref) {
sprintf(nmea, "%6.2f", 123.45); // fail if sprintf() doesn't handle floats
sprintf(nmea, "%6.2f", (double)123.45); // fail if sprintf() doesn't handle floats
if (strcmp(nmea, "123.45"))
return NULL;
*nmea = '$';
@ -82,8 +88,7 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// pruning excess code easier. Otherwise, keep them alphabetical for ease of
// reading.
if (!strcmp(thisSentence,
"GGA")) { //********************************************GGA
if (!strcmp(thisSentence, "GGA")) { //************************************GGA
// GGA Global Positioning System Fix Data. Time, Position and fix related
// data for a GPS receiver
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
@ -107,12 +112,11 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 14) Differential reference station ID, 0000-1023
// 15) Checksum
sprintf(p, "%09.2f,%09.4f,%c,%010.4f,%c,%d,%02d,%f,%f,M,%f,M,,",
hour * 10000L + minute * 100L + seconds + milliseconds / 1000.,
(double)latitude, lat, (double)longitude, lon, fixquality,
satellites, (double)HDOP, (double)altitude, (double)geoidheight);
(double)hour * 10000L + minute * 100L + seconds + milliseconds / 1000.,
(double)latitude, lat, (double)longitude, lon, fixquality, satellites,
(double)HDOP, (double)altitude, (double)geoidheight);
} else if (!strcmp(thisSentence,
"GLL")) { //********************************************GLL
} else if (!strcmp(thisSentence, "GLL")) { //*****************************GLL
// GLL Geographic Position Latitude/Longitude
// 1 2 3 4 5 6 7
// | | | | | | |
@ -125,11 +129,10 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 6) Status A - Data Valid, V - Data Invalid
// 7) Checksum
sprintf(p, "%09.4f,%c,%010.4f,%c,%09.2f,A", (double)latitude, lat,
(double)longitude, lon,
hour * 10000L + minute * 100L + seconds + milliseconds / 1000.);
(double)longitude, lon, (double)hour * 10000L + minute * 100L +
seconds + milliseconds / 1000.);
} else if (!strcmp(thisSentence,
"GSA")) { //********************************************
} else if (!strcmp(thisSentence, "GSA")) { //*****************************GSA
// GSA GPS DOP and active satellites
// 1 2 3 14 15 16 17 18
// | | | | | | | |
@ -146,8 +149,7 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 18) Checksum
return NULL;
} else if (!strcmp(thisSentence,
"RMC")) { //********************************************RMC
} else if (!strcmp(thisSentence, "RMC")) { //*****************************RMC
// RMC Recommended Minimum Navigation Information
// 12
// 1 2 3 4 5 6 7 8 9 10 11 |
@ -166,13 +168,255 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 11) E or W
// 12) Checksum
sprintf(p, "%09.2f,A,%09.4f,%c,%010.4f,%c,%f,%f,%06d,%f,%c",
hour * 10000L + minute * 100L + seconds + milliseconds / 1000.,
(double)hour * 10000L + minute * 100L + seconds + milliseconds / 1000.,
(double)latitude, lat, (double)longitude, lon, (double)speed,
(double)angle, day * 10000 + month * 100 + year,
(double)magvariation, mag);
(double)angle, day * 10000 + month * 100 + year, (double)magvariation, mag);
} else if (!strcmp(thisSentence,
"TXT")) { //********************************************TXT
} else if (!strcmp(thisSentence, "APB")) { //*****************************APB
// APB Autopilot Sentence "B"
// 13 15
// 1 2 3 4 5 6 7 8 9 10 11 12 | 14 |
// | | | | | | | | | | | | | | |
//$--APB,A,A,x.x,a,N,A,A,x.x,a,c--c,x.x,a,x.x,a*hh
// 1) Status
// V = LORAN-C Blink or SNR warning
// A = general warning flag or other navigation systems when a reliable
// fix is not available
// 2) Status
// V = Loran-C Cycle Lock warning flag
// A = OK or not used
// 3) Cross Track Error Magnitude
// 4) Direction to steer, L or R
// 5) Cross Track Units, N = Nautical Miles
// 6) Status
// A = Arrival Circle Entered
// 7) Status
// A = Perpendicular passed at waypoint
// 8) Bearing origin to destination
// 9) M = Magnetic, T = True
// 10) Destination Waypoint ID
// 11) Bearing, present position to Destination
// 12) M = Magnetic, T = True
// 13) Heading to steer to destination waypoint
// 14) M = Magnetic, T = True
// 15) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBK")) { //*****************************DBT
// DBK Depth Below Keel
// 1 2 3 4 5 6 7
// | | | | | | |
//$--DBK,x.x,f,x.x,M,x.x,F*hh
// 1) Depth, feet
// 2) f = feet
// 3) Depth, meters
// 4) M = meters
// 5) Depth, Fathoms
// 6) F = Fathoms
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBS")) { //*****************************DBT
// DBS Depth Below Surface
// 1 2 3 4 5 6 7
// | | | | | | |
//$--DBS,x.x,f,x.x,M,x.x,F*hh
// 1) Depth, feet
// 2) f = feet
// 3) Depth, meters
// 4) M = meters
// 5) Depth, Fathoms
// 6) F = Fathoms
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "DBT")) { //*****************************DBT
// DBT Depth Below Transducer
// 1 2 3 4 5 6 7
// | | | | | | |
//$--DBT,x.x,f,x.x,M,x.x,F*hh
// 1) Depth, feet
// 2) f = feet
// 3) Depth, meters
// 4) M = meters
// 5) Depth, Fathoms
// 6) F = Fathoms
// 7) Checksum
double d = val[NMEA_DEPTH].latest - depthToTransducer;
sprintf(p, "%f,f,%f,M,,,", d / 0.3048, d);
} else if (!strcmp(thisSentence, "DPT")) { //*****************************DPT
// DPT Heading Deviation & Variation
// 1 2 3
// | | |
//$--DPT,x.x,x.x*hh
// 1) Depth, meters
// 2) Offset from transducer;
// positive means distance from transducer to water line,
// negative means distance from transducer to keel
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "GSV")) { //*****************************GSV
// GSV Satellites in view
// 1 2 3 4 5 6 7 n
// | | | | | | | |
//$--GSV,x,x,x,x,x,x,x,...*hh
// 1) total number of messages
// 2) message number
// 3) satellites in view
// 4) satellite number
// 5) elevation in degrees
// 6) azimuth in degrees to true
// 7) SNR in dB
// more satellite infos like 4)-7)
// n) Checksum
return NULL;
} else if (!strcmp(thisSentence, "HDG")) { //*****************************HDG
// HDG Heading Deviation & Variation
// 1 2 3 4 5 6
// | | | | | |
//$--HDG,x.x,x.x,a,x.x,a*hh
// 1) Magnetic Sensor heading in degrees
// 2) Magnetic Deviation, degrees
// 3) Magnetic Deviation direction, E = Easterly, W = Westerly
// 4) Magnetic Variation degrees
// 5) Magnetic Variation direction, E = Easterly, W = Westerly
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "HDM")) { //*****************************HDM
// HDM Heading Magnetic
// 1 2 3
// | | |
//$--HDM,x.x,M*hh
// 1) Heading Degrees, magnetic
// 2) M = magnetic
// 3) Checksum
sprintf(p, "%f,M", (double)val[NMEA_HDG].latest);
} else if (!strcmp(thisSentence, "HDT")) { //*****************************HDT
// HDT Heading True
// 1 2 3
// | | |
//$--HDT,x.x,T*hh
// 1) Heading Degrees, true
// 2) T = True
// 3) Checksum
// starts with $II for integrated instrumentation
sprintf(p, "%f,T", (double)val[NMEA_HDT].latest);
} else if (!strcmp(thisSentence, "MDA")) { //*****************************MDA
// MDA Meteorological Composite
// 1 2 3 4 5 6 7 8 9 10 11 12
// | | | | | | | | | | | |
//$__MDA,x.x,I,x.x,B,x.x,C,x.x,C,x.x, ,x.x,C,,T,,M,,N,,M*hh
//$IIMDA,,I,,B,,C,21.8,C,,,,C,,T,,M,,N,,M*0F // sent by RayMarine i70s
// Speed/Depth/Wind
// 1) Barometric Pressure
// 2) inches of Hg
// 3) Barometric Pressure
// 4) bar
// 5) Atmospheric Temperature
// 6) C or F
// 7) Water Temperature
// 8) C or F
// 9) Relative Humidity
// 10)
// 11) Dew Point
// 12) C or F
return NULL;
} else if (!strcmp(thisSentence, "MTW")) { //*****************************MTW
// MTW Water Temperature
// 1 2 3
// | | |
//$IIMTW,x.x,C*hh
//$IIMTW,21.8,C*18 // sent by RayMarine i70s Speed/Depth/Wind
// 1) Degrees
// 2) Unit of Measurement, Celcius
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "MWD")) { //*****************************MWD
// MWD Wind Direction & Speed
// Format unknown
return NULL;
} else if (!strcmp(thisSentence, "MWV")) { //*****************************MWV
// MWV Wind Speed and Angle assuming values for True
// 1 2 3 4 5 6
// | | | | | |
//$IIMWV,x.x,a,x.x,a,a*hh
//$WIMWV,276.94,R,0,N,A*03 // sent by RayMarine i70s Speed/Depth/Wind
// 1) Wind Angle, 0 to 360 degrees
// 2) Reference, R = Relative, T = True
// 3) Wind Speed
// 4) Wind Speed Units, K/M/N kilometers/miles/knots
// 5) Status, A = Data Valid
// 6) Checksum
if (ref == 'R')
sprintf(p, "%f,%c,%f,N,A", (double)val[NMEA_AWA].latest, ref,
(double)val[NMEA_AWS].latest);
else
sprintf(p, "%f,%c,%f,N,A", (double)val[NMEA_TWA].latest, 'T',
(double)val[NMEA_TWS].latest);
} else if (!strcmp(thisSentence, "RMB")) { //*****************************RMB
// RMB Recommended Minimum Navigation Information
// 1 2 3 4 5 6 7 8 9 10 11 12 13 14
// | | | | | | | | | | | | | |
//$--RMB,A,x.x,a,c--c,c--c,llll.ll,a,yyyyy.yy,a,x.x,x.x,x.x,A*hh
// 1) Status, V = Navigation receiver warning
// 2) Cross Track error - nautical miles
// 3) Direction to Steer, Left or Right
// 4) TO Waypoint ID
// 5) FROM Waypoint ID
// 6) Destination Waypoint Latitude 7) N or S
// 8) Destination Waypoint Longitude 9) E or W
// 10) Range to destination in nautical miles
// 11) Bearing to destination in degrees True
// 12) Destination closing velocity in knots
// 13) Arrival Status, A = Arrival Circle Entered 14) Checksum
sprintf(p, ",,,,,,,,,,,%f,A", (double)val[NMEA_VMGWP].latest);
} else if (!strcmp(thisSentence, "ROT")) { //*****************************ROT
// ROT Rate Of Turn
// 1 2 3
// | | |
//$--ROT,x.x,A*hh
// 1) Rate Of Turn, degrees per minute, "-" means bow turns to port
// 2) Status, A means data is valid
// 3) Checksum
return NULL;
} else if (!strcmp(thisSentence, "RPM")) { //*****************************RPM
// RPM Revolutions
// 1 2 3 4 5 6
// | | | | | |
//$--RPM,a,x,x.x,x.x,A*hh
// 1) Source; S = Shaft, E = Engine
// 2) Engine or shaft number
// 3) Speed, Revolutions per minute
// 4) Propeller pitch, % of maximum, "-" means astern
// 5) Status, A means data is valid
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "RSA")) { //*****************************RSA
// RSA Rudder Sensor Angle
// 1 2 3 4 5
// | | | | |
//$--RSA,x.x,A,x.x,A*hh
// 1) Starboard (or single) rudder sensor, "-" means Turn To Port
// 2) Status, A means data is valid
// 3) Port rudder sensor
// 4) Status, A means data is valid
// 5) Checksum
return NULL;
} else if (!strcmp(thisSentence, "TXT")) { //*****************************TXT
// as mentioned in https://github.com/adafruit/Adafruit_GPS/issues/95
// TXT Text Transmission
// 1 2 3 4 5
@ -185,6 +429,136 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
// 5) Checksum
sprintf(p, "01,01,23,This is the text of the sample message");
} else if (!strcmp(thisSentence, "VDR")) { //*****************************VDR
// VDR Set and Drift
// 1 2 3 4 5 6 7
// | | | | | | |
//$--VDR,x.x,T,x.x,M,x.x,N*hh
// 1) Degress True
// 2) T = True
// 3) Degrees Magnetic
// 4) M = Magnetic
// 5) Knots (speed of current)
// 6) N = Knots
// 7) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VHW")) { //*****************************VHW
// VHW Water Speed and Heading
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
//$--VHW,x.x,T,x.x,M,x.x,N,x.x,K*hh
//$IIVHW,,T,,M,0,N,0,K*55 // sent by RayMarine i70s Speed/Depth/Wind
// 1) Degrees True
// 2) T = True
// 3) Degrees Magnetic
// 4) M = Magnetic
// 5) Knots (speed of vessel relative to the water) [66]
// 6) N = Knots
// 7) Kilometers (speed of vessel relative to the water)
// 8) K = Kilometres
// 9) Checksum
sprintf(p, "%f,T,%f,M,%f,N,%f,K", (double)val[NMEA_HDT].latest,
(double)val[NMEA_HDG].latest, (double)val[NMEA_VTW].latest,
(double)val[NMEA_VTW].latest * 1.829);
} else if (!strcmp(thisSentence, "VLW")) { //*****************************VLW
// VLW Distance Traveled through Water
// 1 2 3 4 5
// | | | | |
//$--VLW,x.x,N,x.x,N*hh
//$IIVLW,0,N,0,N,,N,,N*4D // sent by RayMarine i70s Speed/Depth/Wind
// not sure what the last two are?
// 1) Total cumulative distance
// 2) N = Nautical Miles
// 3) Distance since Reset
// 4) N = Nautical Miles
// 5) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VPW")) { //*****************************VPW
// not supported by iNavX
// VPW Speed Measured Parallel to Wind
// 1 2 3 4 5
// | | | | |
//$--VPW,x.x,N,x.x,M*hh
// 1) Speed, "-" means downwind
// 2) N = Knots
// 3) Speed, "-" means downwind
// 4) M = Meters per second
// 5) Checksum
sprintf(p, "%f,N,,", (double)val[NMEA_VMG].latest);
} else if (!strcmp(thisSentence, "VTG")) { //*****************************VTG
// VTG Track Made Good and Ground Speed
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
//$--VTG,x.x,T,x.x,M,x.x,N,x.x,K*hh
// 1) Track Degrees 2) T = True
// 3) Track Degrees 4) M = Magnetic
// 5) Speed Knots 6) N = Knots
// 7) Speed Kilometers Per Hour 8) K = Kilometres Per Hour
// 9) Checksum
return NULL;
} else if (!strcmp(thisSentence, "VWR")) { //*****************************VWR
// VWR Relative Wind Speed and Angle
// 1 2 3 4 5 6 7 8 9
// | | | | | | | | |
//$--VWR,x.x,a,x.x,N,x.x,M,x.x,K*hh
//$WIVWR,83.1,L,0,N,0,M,0,K*6D // sent by RayMarine i70s
// Speed/Depth/Wind
// 1) Wind direction magnitude in degrees
// 2) Wind direction Left/Right of bow
// 3) Speed
// 4) N = Knots
// 5) Speed
// 6) M = Meters Per Second
// 7) Speed
// 8) K = Kilometers Per Hour
// 9) Checksum
return NULL;
} else if (!strcmp(thisSentence, "WCV")) { //*****************************WCV
// WCV Waypoint Closure Velocity
// 1 2 3 4
// | | | |
//$--WCV,x.x,N,c--c*hh
// 1) Velocity 2) N = knots 3) Waypoint ID 4) Checksum
sprintf(p, "%f,N,home", (double)val[NMEA_VMG].latest);
} else if (!strcmp(thisSentence, "XTE")) { //*****************************XTE
// XTE Cross-Track Error Measured
// 1 2 3 4 5 6
// | | | | | |
//$--XTE,A,A,x.x,a,N,*hh
// 1) Status
// V = LORAN-C blink or SNR warning
// A = general warning flag or other navigation systems when a reliable
// fix is not available
// 2) Status
// V = Loran-C cycle lock warning flag
// A = OK or not used
// 3) Cross track error magnitude
// 4) Direction to steer, L or R
// 5) Cross track units. N = Nautical Miles
// 6) Checksum
return NULL;
} else if (!strcmp(thisSentence, "ZDA")) { //*****************************ZDA
// ZDA Time & Date UTC, Day, Month, Year and Local Time Zone
// 1 2 3 4 5 6 7
// | | | | | | |
//$--ZDA,hhmmss.ss,xx,xx,xxxx,xx,xx*hh
// 1) Local zone minutes description, same sign as local hours
// 2) Local zone description, 00 to +/- 13 hours
// 3) Year
// 4) Month, 01 to 12
// 5) Day, 01 to 31
// 6) Time (UTC)
// 7) Checksum
return NULL;
} else {
return NULL; // didn't find a match for the build request
}
@ -196,3 +570,24 @@ char *Adafruit_GPS::build(char *nmea, const char *thisSource,
}
#endif // NMEA_EXTENSIONS
/**************************************************************************/
/*!
@brief Add *CS where CS is the two character hex checksum for all but
the first character in the string. The checksum is the result of an
exclusive or of all the characters in the string. Also useful if you
are creating new PMTK strings for controlling a GPS module and need a
checksum added.
@param buff Pointer to the string, which must be long enough
@return none
*/
/**************************************************************************/
void Adafruit_GPS::addChecksum(char *buff) {
char cs = 0;
int i = 1;
while (buff[i]) {
cs ^= buff[i];
i++;
}
sprintf(buff, "%s*%02X", buff, cs);
}