package lejos.addon.gps; import java.io.*; import java.util.*; /** * This class manages a data received from a GPS Device. * GPS Class manages the following NMEA Sentences: * * GPRMC * GPGSV * GPGSA * GPGGA (superclass) * GPVTG (superclass) * * @author BB * @author Juan Antonio Brenha Moral * */ /* * DEVELOPER NOTES: More NMEA sentence types that can be added if there is demand for them: * http://www.gpsinformation.org/dale/nmea.htm */ public class GPS extends SimpleGPS { //Classes which manages GGA, RMC, VTG, GSV, GSA Sentences private RMCSentence rmcSentence; private GSVSentence gsvSentence; private int gsvSentenceNumber = -1; private int gsvSentenceTotal = -1; //Date Object with use GGA & RMC Sentence private Date date; /** * The constructor. It needs an InputStream * * @param in An input stream from the GPS receiver */ public GPS(InputStream in) { super(in); rmcSentence = new RMCSentence(); gsvSentence = new GSVSentence(); date = new Date(); } /* GETTERS & SETTERS */ /** * Return Compass Degrees * in a range: 0.0-359.9 * * @return the compass degrees */ public float getCompassDegrees(){ return rmcSentence.getCompassDegrees(); } /** * Return a Date Object with data from GGA and RMC NMEA Sentence * * @return the date */ public Date getDate(){ // TODO: Would be more proper to return a new Date object instead of recycled Date. updateDate(); updateTime(); return date; } /** * * Get NMEA Satellite. The satellite list is retrieved from the almanac data. Satellites are * ordered by their elevation: highest elevation (index 0) -> lowest elevation. * * @param index the satellite index * @return the NMEASaltellite object for the selected satellite */ public Satellite getSatellite(int index){ Satellite s = gsvSentence.getSatellite(index); // Compare getPRN() with this satellite, fill in setTracked(): // TODO: This fails because most satellites are set to 0 when this is called. Not synced yet. boolean tracked = false; int [] prns = getPRN(); for(int i=0;i<prns.length;i++) { if(prns[i] == s.getPRN()) tracked=true; break; } s.setTracked(tracked); return s; } /* TODO: Might be worth overwriting the SimpleGPS method for lat, long, speed, course, and maybe time because they can be gotten from two sources (RMC). Perhaps check if == -1, if so try getting it from another sentence. Also check time-stamp for both to see which is more recent. */ /* ANSWER: With Holux-1200, GGA gets values before RMC. Ignore RMC? */ /** * Returns the number of satellites being tracked to * determine the coordinates. This method overwrites the superclass method * and returns the number from the GSV sentence. * * @return Number of satellites e.g. 8 */ public int getSatellitesTracked(){ return ggaSentence.getSatellitesTracked(); } /** * The satellites in view is a list of satellites the GPS could theoretically connect to (i.e. satellites that * are not over the earth's horizon). The getSatellitesInView() method will always return an equal or greater * number than getSatellitesTracked(). * * @return Number of satellites e.g. 8 */ public int getSatellitesInView(){ return gsvSentence.getSatellitesInView(); } /** * Internal helper method to aid in the subclass architecture. Overwrites the superclass * method and calls it internally. * * @param header * @param s */ protected void sentenceChooser(String header, String s) { if (header.equals(RMCSentence.HEADER)){ rmcSentence.setSentence(s); notifyListeners(this.rmcSentence); }else if (header.equals(GSVSentence.HEADER)){ // TODO: I wonder what happens if say 2 of 4 are received and parse is called? // Because 2 would be new data, 2 would be old data. // Can't happen because parse() only called when not null. // BUT what if it is in the middle of parsing and new data comes in? // Solution: Sync GSVSentence.parse()? checkRefresh() is already synced though. // 0. Get StringTokenizer to read info from NMEASentence: StringTokenizer st = new StringTokenizer(s,","); st.nextToken(); // Skip header $GPGSV // 1.1 Find out how many sentences in sequence. gsvSentenceTotal = Integer.parseInt(st.nextToken()); // 1.2 Find out which sentence this is. gsvSentenceNumber = Integer.parseInt(st.nextToken()); // 2. Assign sentence to GSVSentence in order. gsvSentence.setSentence(s, gsvSentenceNumber, gsvSentenceTotal); // 3. If last sentence: if(gsvSentenceTotal == gsvSentenceNumber) { // 3a. setSentence() to last one so it is not null gsvSentence.setSentence(s); // 3b. Notify GPSListener notifyListeners(this.gsvSentence); } } else super.sentenceChooser(header, s); // Check superclass sentences. } /* NMEA */ /** * Update Time values */ private void updateTime(){ int timeStamp = ggaSentence.getTime(); if(timeStamp >0) { String rt = Integer.toString(timeStamp); int hh = Integer.parseInt(rt.substring(0, rt.length() - 4)); int mm = Integer.parseInt(rt.substring(rt.length() - 4, rt.length()-2)); int ss = Integer.parseInt(rt.substring(rt.length()-2, rt.length())); date.setHours(hh); date.setMinutes(mm); date.setSeconds(ss); } } /** * Update Date values */ private void updateDate(){ int dateStamp = rmcSentence.getDate(); if(dateStamp > 0) { String rd = Integer.toString(dateStamp); int dd = Integer.parseInt(rd.substring(0, rd.length() - 4)); int mm = Integer.parseInt(rd.substring(rd.length() - 4, rd.length()-2)); int yy = Integer.parseInt(rd.substring(rd.length()-2, rd.length())); date.setDay(dd); date.setMonth(mm); date.setYear(yy); } } }