1 /***************************************************************************
2 *
3 * Project: OpenCPN
4 * Purpose: NMEA0183 Support Classes
5 * Author: Samuel R. Blackburn, David S. Register
6 *
7 ***************************************************************************
8 * Copyright (C) 2010 by Samuel R. Blackburn, David S Register *
9 * *
10 * This program is free software; you can redistribute it and/or modify *
11 * it under the terms of the GNU General Public License as published by *
12 * the Free Software Foundation; either version 2 of the License, or *
13 * (at your option) any later version. *
14 * *
15 * This program is distributed in the hope that it will be useful, *
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
18 * GNU General Public License for more details. *
19 * *
20 * You should have received a copy of the GNU General Public License *
21 * along with this program; if not, write to the *
22 * Free Software Foundation, Inc., *
23 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
24 ***************************************************************************
25 *
26 * S Blackburn's original source license: *
27 * "You can use it any way you like." *
28 * More recent (2010) license statement: *
29 * "It is BSD license, do with it what you will" *
30 */
31
32
33 #include "nmea0183.h"
34
35 /*
36 ** Author: Samuel R. Blackburn
37 ** CI$: 76300,326
38 ** Internet: sammy@sed.csc.com
39 **
40 ** You can use it any way you like.
41 */
42
43
RMC()44 RMC::RMC()
45 {
46 Mnemonic = _T("RMC");
47 Empty();
48 }
49
~RMC()50 RMC::~RMC()
51 {
52 Mnemonic.Empty();
53 Empty();
54 }
55
Empty(void)56 void RMC::Empty( void )
57 {
58
59 UTCTime.Empty();
60 IsDataValid = Unknown0183;
61 SpeedOverGroundKnots = 0.0;
62 Position.Empty();
63 TrackMadeGoodDegreesTrue = 0.0;
64 Date.Empty();
65 MagneticVariation = 0.0;
66 MagneticVariationDirection = EW_Unknown;
67 }
68
Parse(const SENTENCE & sentence)69 bool RMC::Parse( const SENTENCE& sentence )
70 {
71 // ASSERT_VALID( this );
72
73 /*
74 ** RMC - Recommended Minimum Navigation Information
75 **
76 ** Version 2.0 Format
77 ** 12
78 ** 1 2 3 4 5 6 7 8 9 10 11|
79 ** | | | | | | | | | | | |
80 ** $--RMC,hhmmss.ss,A,llll.ll,a,yyyyy.yy,a,x.x,x.x,xxxx,x.x,a*hh<CR><LF>
81 **
82 ** Field Number:
83 ** 1) UTC Time
84 ** 2) Status, V = Navigation receiver warning
85 ** 3) Latitude
86 ** 4) N or S
87 ** 5) Longitude
88 ** 6) E or W
89 ** 7) Speed over ground, knots
90 ** 8) Track made good, degrees true
91 ** 9) Date, ddmmyy
92 ** 10) Magnetic Variation, degrees
93 ** 11) E or W
94
95 ** Version 2.0
96 ** 12) Checksum
97
98 ** Version 2.3
99 ** 12) Mode (D or A), optional, may be NULL
100 ** 13) Checksum
101 */
102
103 /*
104 ** First we check the checksum...
105 */
106
107 NMEA0183_BOOLEAN check = sentence.IsChecksumBad( 12 );
108
109 if ( check == NTrue )
110 {
111 /*
112 ** This may be an NMEA Version 2.3 sentence, with "Mode" field
113 */
114 wxString checksum_in_sentence = sentence.Field( 12 );
115 if(checksum_in_sentence.StartsWith(_T("*"))) // Field is a valid erroneous checksum
116 {
117 SetErrorMessage( _T("Invalid Checksum") );
118 return( FALSE );
119 }
120 else
121 {
122 check = sentence.IsChecksumBad( 13 );
123 if( check == NTrue)
124 {
125 SetErrorMessage( _T("Invalid Checksum") );
126 return( FALSE );
127 }
128 }
129 }
130
131 // Is this a 2.3 message?
132 bool bext_valid = true;
133 wxString checksum_in_sentence = sentence.Field( 12 );
134 if(!checksum_in_sentence.StartsWith(_T("*"))) {
135 if(checksum_in_sentence == _T("N") )
136 bext_valid = false;
137 }
138
139
140 UTCTime = sentence.Field( 1 );
141
142 IsDataValid = sentence.Boolean( 2 );
143 if( !bext_valid )
144 IsDataValid = NFalse;
145
146 Position.Parse( 3, 4, 5, 6, sentence );
147 SpeedOverGroundKnots = sentence.Double( 7 );
148 TrackMadeGoodDegreesTrue = sentence.Double( 8 );
149 Date = sentence.Field( 9 );
150 MagneticVariation = sentence.Double( 10 );
151 MagneticVariationDirection = sentence.EastOrWest( 11 );
152
153 return( TRUE );
154 }
155
Write(SENTENCE & sentence)156 bool RMC::Write( SENTENCE& sentence )
157 {
158 // ASSERT_VALID( this );
159
160 /*
161 ** Let the parent do its thing
162 */
163
164 RESPONSE::Write( sentence );
165
166 sentence += UTCTime;
167 sentence += IsDataValid;
168 sentence += Position;
169 sentence += SpeedOverGroundKnots;
170 sentence += TrackMadeGoodDegreesTrue;
171 sentence += Date;
172
173 if(MagneticVariation > 360.)
174 sentence += _T(",,");
175 else
176 {
177 sentence += MagneticVariation;
178 sentence += MagneticVariationDirection;
179 }
180
181 sentence.Finish();
182
183 return( TRUE );
184 }
185
operator =(const RMC & source)186 const RMC& RMC::operator = ( const RMC& source )
187 {
188 // ASSERT_VALID( this );
189
190 UTCTime = source.UTCTime;
191 IsDataValid = source.IsDataValid;
192 Position = source.Position;
193 SpeedOverGroundKnots = source.SpeedOverGroundKnots;
194 TrackMadeGoodDegreesTrue = source.TrackMadeGoodDegreesTrue;
195 Date = source.Date;
196 MagneticVariation = source.MagneticVariation;
197 MagneticVariationDirection = source.MagneticVariationDirection;
198
199 return( *this );
200 }
201