source: josm/trunk/src/org/openstreetmap/josm/io/NmeaReader.java@ 1073

Last change on this file since 1073 was 1056, checked in by mfloryan, 17 years ago

Fixes a bug introduced in revision 1049 and thus properly closes bug
#1626 - NMEA files can now be opened properly

File size: 5.2 KB
Line 
1//License: GPL. Copyright 2008 by Christoph Brill
2
3package org.openstreetmap.josm.io;
4
5import java.io.BufferedReader;
6import java.io.File;
7import java.io.IOException;
8import java.io.InputStream;
9import java.io.InputStreamReader;
10import java.util.ArrayList;
11import java.util.Arrays;
12import java.util.Collection;
13
14import org.openstreetmap.josm.data.coor.LatLon;
15import org.openstreetmap.josm.data.gpx.GpxData;
16import org.openstreetmap.josm.data.gpx.GpxTrack;
17import org.openstreetmap.josm.data.gpx.WayPoint;
18
19/**
20 * Read a nmea file. Based on information from
21 * http://www.kowoma.de/gps/zusatzerklaerungen/NMEA.htm
22 *
23 * @author cbrill
24 */
25public class NmeaReader {
26
27 /** Handler for the different types that NMEA speaks. */
28 public static enum NMEA_TYPE {
29
30 /** RMC = recommended minimum sentence C. */
31 GPRMC("$GPRMC"),
32 /** GPS positions. */
33 GPGGA("$GPGGA"),
34 /** SA = satellites active. */
35 GPGSA("$GPGSA");
36
37 private final String type;
38
39 NMEA_TYPE(String type) {
40 this.type = type;
41 }
42
43 public String getType() {
44 return this.type;
45 }
46
47 public boolean equals(String type) {
48 return this.type.equals(type);
49 }
50 }
51
52 private static final int TYPE = 0;
53
54 // The following only applies to GPRMC
55 public static enum GPRMC {
56 TIME(1),
57 /** Warning from the receiver (A = data ok, V = warning) */
58 RECEIVER_WARNING(2),
59 WIDTH_NORTH(3), WIDTH_NORTH_NAME(4),
60 LENGTH_EAST(5), LENGTH_EAST_NAME(6),
61 /** Speed in knots */
62 SPEED(7), COURSE(8), DATE(9),
63 /** magnetic declination */
64 MAGNETIC_DECLINATION(10), UNKNOWN(11),
65 /**
66 * Mode (A = autonom; D = differential; E = estimated; N = not valid; S
67 * = simulated)
68 *
69 * @since NMEA 2.3
70 */
71 MODE(12);
72
73 public final int position;
74
75 GPRMC(int position) {
76 this.position = position;
77 }
78 }
79
80 // The following only applies to GPGGA
81 public static enum GPGGA {
82 TIME(1), LATITUDE(2), LATITUDE_NAME(3), LONGITUDE(4), LONGITUDE_NAME(5),
83 /**
84 * Quality (0 = invalid, 1 = GPS, 2 = DGPS, 6 = estimanted (@since NMEA
85 * 2.3))
86 */
87 QUALITY(6), SATELLITE_COUNT(7),
88 /** HDOP (horizontal dilution of precision) */
89 HDOP(8),
90 /** height above NN (above geoid) */
91 HEIGHT(9), HEIGHT_UNTIS(10),
92 /** height geoid - height ellipsoid (WGS84) */
93 HEIGHT_2(11), HEIGHT_2_UNTIS(12);
94
95 public final int position;
96
97 GPGGA(int position) {
98 this.position = position;
99 }
100 }
101
102 // The following only applies to GPGGA
103 public static enum GPGSA {
104 AUTOMATIC(1),
105 /** 1 = not fixed, 2 = 2D fixed, 3 = 3D fixed) */
106 FIX_TYPE(2),
107 // PRN numbers for max 12 satellites
108 PRN_1(3), PRN_2(4), PRN_3(5), PRN_4(6), PRN_5(7), PRN_6(8), PRN_7(9), PRN_8(
109 10), PRN_9(11), PRN_10(12), PRN_11(13), PRN_12(14),
110 /** PDOP (precision) */
111 PDOP(15),
112 /** HDOP (horizontal precision) */
113 HDOP(16),
114 /** VDOP (vertical precision) */
115 VDOP(17), ;
116
117 public final int position;
118
119 GPGSA(int position) {
120 this.position = position;
121 }
122 }
123
124 public GpxData data;
125
126 public NmeaReader(InputStream source, File relativeMarkerPath) {
127 data = new GpxData();
128 GpxTrack currentTrack = new GpxTrack();
129 Collection<WayPoint> currentTrackSeg = new ArrayList<WayPoint>();
130 currentTrack.trackSegs.add(currentTrackSeg);
131 data.tracks.add(currentTrack);
132
133 BufferedReader rd;
134 String nmeaWithChecksum;
135
136 try {
137 rd = new BufferedReader(new InputStreamReader(source));
138 while ((nmeaWithChecksum = rd.readLine()) != null) {
139 String[] nmeaAndChecksum = nmeaWithChecksum.split("\\*");
140 String nmea = nmeaAndChecksum[0];
141 // XXX: No need for it: String checksum = nmeaAndChecksum[1];
142 String[] e = nmea.split(",");
143 if (e.length == 0) {
144 continue;
145 }
146 if (NMEA_TYPE.GPRMC.equals(e[TYPE])) {
147 LatLon latLon = parseLatLon(e);
148 if (latLon == null) {
149 continue;
150 }
151 WayPoint currentWayPoint = new WayPoint(latLon);
152 currentTrackSeg.add(currentWayPoint);
153 }
154 }
155 rd.close();
156 } catch (final IOException e) {
157 System.out.println("Error reading file");
158 }
159
160 }
161
162 private LatLon parseLatLon(String[] e) throws NumberFormatException {
163 // If the array looks bogus don't try to get valuable information from it
164 // But remember that the array is stripped of checksum and GPRMC is only 12 elements and split strips empty trailing elements
165 if (e.length < 10) {
166 return null;
167 }
168 String widthNorth = e[GPRMC.WIDTH_NORTH.position].trim();
169 String lengthEast = e[GPRMC.LENGTH_EAST.position].trim();
170 if ("".equals(widthNorth) || "".equals(lengthEast)) {
171 return null;
172 }
173
174 // The format is xxDDLL.LLLL
175 // xx optional whitespace
176 // DD (int) degres
177 // LL.LLLL (double) latidude
178 int latdegsep = widthNorth.indexOf('.') - 2;
179 if (latdegsep < 0) {
180 return null;
181 }
182 int latdeg = Integer.parseInt(widthNorth.substring(0, latdegsep));
183 double latmin = Double.parseDouble(widthNorth.substring(latdegsep));
184 double lat = latdeg + latmin / 60;
185 if ("S".equals(e[GPRMC.WIDTH_NORTH_NAME.position])) {
186 lat = -lat;
187 }
188
189 int londegsep = lengthEast.indexOf('.') - 2;
190 if (londegsep < 0) {
191 return null;
192 }
193 int londeg = Integer.parseInt(lengthEast.substring(0, londegsep));
194 double lonmin = Double.parseDouble(lengthEast.substring(londegsep));
195 double lon = londeg + lonmin / 60;
196 if ("W".equals(e[GPRMC.LENGTH_EAST_NAME.position])) {
197 lon = -lon;
198 }
199
200 return new LatLon(lat, lon);
201 }
202}
Note: See TracBrowser for help on using the repository browser.