2 Copyright 2006 Johnathan Corgan.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2
6 as published by the Free Software Foundation.
8 This software is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with GNU Radio; see the file COPYING. If not, write to
15 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16 Boston, MA 02111-1307, USA.
19 // Application level includes
26 #define NMEA_BAUD 4800
27 #define NMEA_BUFSIZE 82 // Maximum NMEA sentence length
29 const wxEventType wxEVT_GPS_UPDATE = wxNewEventType();
31 GPSUpdate::GPSUpdate(const wxEventType &event, GPRMC *gprmc) :
37 GPSBackground::GPSBackground(GPS *gps)
39 wxLogDebug(_T("GPSBackground::GPSBackground()"));
44 m_port = gps->GetPort();
48 // It's in thread.h but somehow gets undef'd
49 typedef void *ExitCode;
50 ExitCode GPSBackground::Entry()
52 wxLogDebug(_T("GPSBackground::GPSBackground: entry"));
55 while (!TestDestroy())
59 wxLogDebug(_T("GPSBackground::GPSBackground: exit"));
62 void GPSBackground::PerLoop()
64 static char buffer[NMEA_BUFSIZE];
65 static int offset = 0;
67 while(m_port->RxReady() > 0) {
68 while (offset < NMEA_BUFSIZE) {
69 // Read a byte into the buffer from the GPS data
70 if (m_port->Read(&buffer[offset], 1) != 1)
71 return; // No more to read or read error/timeout, bail
73 // Test for end of NMEA message
74 if (buffer[offset] == '\r' || buffer[offset] == '\n') {
75 buffer[offset] = '\0'; // Append end of string null
77 m_gps->RxData(buffer);
84 wxLogDebug(_T("GPSBackground: discarding too long input"));
91 GPS::GPS(wxEvtHandler *dest)
93 wxLogDebug(_T("GPS::GPS()"));
100 wxLogDebug(_T("GPS::~GPS()"));
103 bool GPS::Start(wxString &port)
105 wxLogDebug(_T("GPS::Start(): %s"), port.c_str());
106 m_port = new SerialPort(port);
108 if (m_port->Open(NMEA_BAUD) == false) {
113 m_thread = new GPSBackground(this);
120 wxLogDebug(_T("GPS::Stop()"));
122 if (m_thread && m_thread->IsRunning()) {
124 while (m_thread->IsRunning()) {
138 bool NMEA::Checksum(char *sentence)
140 unsigned char checksum = '\0';
141 char ch, *pos = sentence, ctxt[3];
143 while ((ch = *pos++) != '*' && ch != '\0')
146 sprintf(ctxt, "%02X", checksum);
147 if (strncmp(ctxt, pos, 2))
153 char *NMEA::Field(char *sentence, int num)
155 static char result[NMEA_BUFSIZE];
156 char ch, *pos = sentence;
159 while ((ch = *pos++) != ',' && ch != '\0')
162 strncpy(result, pos, NMEA_BUFSIZE-1);
165 while (*pos && *pos != ',' && *pos != '*' && *pos != '\r' && ++i < NMEA_BUFSIZE)
172 double NMEA::Coord(char *sentence, int num)
174 double coord, degrees, minutes;
176 sscanf(Field(sentence, num), "%lf", &coord);
177 minutes = 100.0*modf(coord/100.0, °rees);
178 coord = degrees+minutes/60.0;
180 char *ptr = Field(sentence, num+1);
181 if (*ptr == 'S' || *ptr == 'W')
187 void GPS::RxData(char *buffer)
191 if (NMEA::Checksum(buffer+1)) {
192 if (strncmp("$GPRMC", buffer, 6) == 0) {
193 GPRMC *fix = new GPRMC(buffer);
194 GPSUpdate update(wxEVT_GPS_UPDATE, fix);
195 wxPostEvent(m_dest, update);
199 wxLogDebug(_T("GPS::RxData: NMEA checksum failed for input"));
202 GPRMC::GPRMC(char *sentence)
209 char *p = Field(sentence, 1);
211 strncpy(digits, p, 2);
212 stamp.tm_hour = atoi(digits);
213 strncpy(digits, p+2, 2);
214 stamp.tm_min = atoi(digits);
215 strncpy(digits, p+4, 2);
216 stamp.tm_sec = atoi(digits);
218 p = Field(sentence, 9);
220 strncpy(digits, p, 2);
221 stamp.tm_mday = atoi(digits);
222 strncpy(digits, p+2, 2);
223 stamp.tm_mon = atoi(digits)-1;
224 strncpy(digits, p+4, 2);
225 stamp.tm_year = atoi(digits)+100;
227 m_stamp = mktime(&stamp);
228 m_valid = !strcmp(Field(sentence, 2), "A");
229 m_fix.SetLatitude(Coord(sentence, 3));
230 m_fix.SetLongitude(Coord(sentence, 5));
231 sscanf(Field(sentence, 7), "%f", &m_speed);
232 sscanf(Field(sentence, 8), "%f", &m_heading);
233 sscanf(Field(sentence, 10), "%f", &m_magnetic);
234 if (!strcmp(Field(sentence, 11), "W"))
235 m_magnetic = -m_magnetic;
236 m_mode = *Field(sentence, 12);
239 void GPRMC::AsString(char *buf)
241 sprintf(buf, "%s %lf %lf %f %f %f, %s",
245 m_speed, m_heading, m_magnetic,
246 m_valid ? "valid" : "invalid");