Statistics
| Revision:

svn-gvsig-desktop / trunk / extensions / extGPS / src / org / gvsig / gps / GPSDriver.java @ 4829

History | View | Annotate | Download (14 KB)

1
/* gvSIG. Sistema de Informaci?n Geogr?fica de la Generalitat Valenciana
2
 *
3
 * Copyright (C) 2005 IVER T.I. and Generalitat Valenciana.
4
 *
5
 * This program is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU General Public License
7
 * as published by the Free Software Foundation; either version 2
8
 * of the License, or (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,USA.
18
 *
19
 * For more information, contact:
20
 *
21
 *  Generalitat Valenciana
22
 *   Conselleria d'Infraestructures i Transport
23
 *   Av. Blasco Ib??ez, 50
24
 *   46010 VALENCIA
25
 *   SPAIN
26
 *
27
 *      +34 963862235
28
 *   gvsig@gva.es
29
 *      www.gvsig.gva.es
30
 *
31
 *    or
32
 *
33
 *   IVER T.I. S.A
34
 *   Salamanca 50
35
 *   46005 Valencia
36
 *   Spain
37
 *
38
 *   +34 963163400
39
 *   dac@iver.es
40
 */
41

    
42
/* CVS MESSAGES:
43
*
44
* $Id: GPSDriver.java 4829 2006-04-12 10:03:32Z jaume $
45
* $Log$
46
* Revision 1.11  2006-04-12 10:03:32  jaume
47
* *** empty log message ***
48
*
49
* Revision 1.10  2006/04/11 20:01:18  jaume
50
* *** empty log message ***
51
*
52
* Revision 1.9  2006/04/11 13:25:54  jaume
53
* *** empty log message ***
54
*
55
* Revision 1.8  2006/04/11 13:19:51  jaume
56
* *** empty log message ***
57
*
58
* Revision 1.7  2006/04/10 11:21:52  jaume
59
* *** empty log message ***
60
*
61
* Revision 1.6  2006/04/07 12:45:55  jaume
62
* *** empty log message ***
63
*
64
* Revision 1.5  2006/04/07 11:10:26  jaume
65
* *** empty log message ***
66
*
67
* Revision 1.4  2006/04/07 08:27:48  jaume
68
* *** empty log message ***
69
*
70
* Revision 1.3  2006/04/06 10:34:46  jaume
71
* *** empty log message ***
72
*
73
* Revision 1.1  2006/04/05 17:08:18  jaume
74
* *** empty log message ***
75
*
76
* Revision 1.2  2006/04/03 21:07:35  jaume
77
* *** empty log message ***
78
*
79
* Revision 1.1  2006/04/03 16:10:27  jaume
80
* *** empty log message ***
81
*
82
* Revision 1.1  2006/03/31 09:55:34  jaume
83
* *** empty log message ***
84
*
85
*
86
*/
87
package org.gvsig.gps;
88

    
89
import gnu.io.CommPortIdentifier;
90
import gnu.io.PortInUseException;
91
import gnu.io.SerialPort;
92
import gnu.io.UnsupportedCommOperationException;
93

    
94
import java.awt.geom.Point2D;
95
import java.io.BufferedWriter;
96
import java.io.File;
97
import java.io.FileWriter;
98
import java.io.IOException;
99
import java.io.InputStream;
100
import java.io.OutputStream;
101
import java.util.ArrayList;
102
import java.util.Enumeration;
103
import java.util.Hashtable;
104
import java.util.Iterator;
105

    
106
import org.gvsig.gps.exceptions.GPSReceiverException;
107
import org.gvsig.gps.listeners.GPSEventListener;
108
import org.gvsig.gps.parser.NMEA.GGASentence;
109
import org.gvsig.gps.parser.NMEA.GSASentence;
110
import org.gvsig.gps.parser.NMEA.IllegalSentenceException;
111
import org.gvsig.gps.parser.NMEA.NMEASentence;
112
import org.gvsig.gps.parser.NMEA.NMEASentenceFactory;
113
import org.gvsig.gps.parser.NMEA.RMCSentence;
114
import org.gvsig.gps.parser.NMEA.VTGSentence;
115

    
116
import com.iver.andami.PluginServices;
117

    
118
/**
119
 * Singleton class that handles the communication within the application and the
120
 * GPS receiver. It opens the port set with the setPort() method and establishes
121
 * the comunication via NMEA protocol.<br>
122
 * 
123
 * @author jaume dominguez faus - jaume.dominguez@iver.es
124
 *
125
 */
126
public class GPSDriver extends Thread {
127
        private boolean connected = false;
128
        private ArrayList eventListeners = new ArrayList();
129
        
130
        // The timeOut field specifies how long a value received from the device
131
        // is valid. After this time, no more events of the corresponding class
132
        // will be fired.
133
        private static final long timeOut = 60 * 1000; // 60 seconds.
134
        
135
        private SerialPort serialPort = null;
136
        private InputStream inputStream;
137
        private OutputStream outputStream;
138

    
139
        private Hashtable register        = new Hashtable();
140
        private int rate = 1000;
141
        private long lastSampleTime;
142
        private boolean eventsEnabled;
143

    
144
        private double lonOffset = 0D;
145
        private double latOffset = 0D;
146

    
147
        private Point2D currentPos;
148
        
149
        private static GPSDriver instance = null;
150
        
151
        
152
        
153
        private static String fileName = "c:/gps points.txt";
154
        static BufferedWriter bw ;
155
        
156
        /**
157
         * Public instantiation of the driver is forbidden.
158
         */
159
        private GPSDriver() {};
160
        
161
        public static GPSDriver getInstance() {
162
                if (instance == null) 
163
                        instance = new GPSDriver();
164
                if (bw == null)
165
                        try {
166
                                bw = new BufferedWriter(new FileWriter(new File(fileName)));
167
                        } catch (IOException e) {
168
                                e.printStackTrace();
169
                        }
170
                return instance;
171
        }
172
        
173
        /**
174
         * 
175
         * @param portID
176
         * @param portSpeed
177
         * @param parity 
178
         * @param stopBits 
179
         * @param dataBits 
180
         * @throws PortInUseException
181
         */
182
        public void setPort(CommPortIdentifier portID, int portSpeed, int dataBits, int stopBits, int parity) throws PortInUseException{
183
                close();
184
                getInstance().serialPort = (SerialPort) portID.open("gvSIG", portSpeed);
185
                try {
186
                        getInstance().inputStream = getInstance().serialPort.getInputStream();
187
                        getInstance().outputStream = getInstance().serialPort.getOutputStream();
188
                        getInstance().serialPort.setSerialPortParams(
189
                                                                portSpeed, 
190
                                                                dataBits,
191
                                                                stopBits,
192
                                                                parity
193
                                                );
194
                } catch (UnsupportedCommOperationException e) {
195
                        e.printStackTrace();
196
                } catch (IOException e) {
197
                        e.printStackTrace();
198
                }
199
        }
200
        
201
        /**
202
         * Tells the driver to start monitoring and capturing data from the device.
203
         */
204
        public void connect() {
205
                getInstance().eventsEnabled = true;
206
                
207
                if (!getInstance().isAlive()) {
208
                        System.out.println("start");
209
                        getInstance().start();        
210
                }
211
        }
212
        
213
        public void run() {
214
                byte[] readBuffer = new byte[2048];
215
                StringBuffer line = new StringBuffer();
216
                try {
217
                        for (int bytes = getInstance().inputStream.read(readBuffer); bytes>-1; bytes = getInstance().inputStream.read(readBuffer)){
218
                                
219
                                // Notify the listeners that the GPS is connected.
220
                                Iterator it = eventListeners.iterator();
221
                                while (!getInstance().connected && getInstance().eventsEnabled && it.hasNext()) {
222
                                        GPSEventListener l = (GPSEventListener) it.next();
223
                                        l.connectionEstablished();
224
                                        
225
                                }
226
                                getInstance().connected = true;
227
                                
228
                                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
229
                                String str = new String(readBuffer).substring(0, bytes);
230
                                int i = str.indexOf("\n");
231
                                if (i == -1) {
232
                                        line.append(str);
233
                                } else {
234
                                        line.append(str.substring(0,i));
235
                                        analyzeMessage(line.toString());
236
                                        
237
                                        line = new StringBuffer();
238
                                        line.append(str.substring(i+1,str.length()));
239
                                }
240
                        }
241
                        System.err.println("Sending request");
242
                        getInstance().outputStream.write(new String("$PMCAG,005,1,GGA,001").getBytes());
243
                        for (int bytes = getInstance().inputStream.read(readBuffer); bytes>-1; bytes = getInstance().inputStream.read(readBuffer)){
244
                                // Creates a new buffer to contain the previous readed bytes and the next bunch of bytes
245
                                String str = new String(readBuffer).substring(0, bytes);
246
                                int i = str.indexOf("\n");
247
                                if (i == -1) {
248
                                        line.append(str);
249
                                } else {
250
                                        line.append(str.substring(0,i));
251
                                        analyzeMessage(line.toString());
252
                                        
253
                                        line = new StringBuffer();
254
                                        line.append(str.substring(i+1,str.length()));
255
                                }
256
                                break;
257
                        }
258
                getInstance().inputStream = null;
259
                getInstance().outputStream = null;
260
                } catch (IOException e) {
261
                        e.printStackTrace();
262
                } catch (NullPointerException e) {
263
                }
264
                
265
                // Connection lost, will notify the listeners
266
                getInstance().connected = false;
267
                Iterator it = getInstance().eventListeners.iterator();
268
                while (getInstance().eventsEnabled && it.hasNext()) {
269
                        GPSEventListener l = (GPSEventListener) it.next();
270
                        l.connectionLost();
271
                }
272
                
273
        }
274
        
275
        private void analyzeMessage(String line) {
276
                try {
277
                        System.out.println("Analizing: "+line);
278
                        NMEASentence data = NMEASentenceFactory.createFromString(line);
279
                        NMEASentence oldData = (NMEASentence) getInstance().register.get(data.getName());
280
                        boolean mustNotifyListeners = !data.isEquivalentTo(oldData);
281
                        getInstance().register.put(data.getName(), data);
282
                        //if (mustNotifyListeners)
283
                                fireEvents();
284
                } catch (IllegalSentenceException e) {
285
                }
286
                
287
        }
288
        
289
        public static void sleep(long millis) {
290
                getInstance().sleep(millis);
291
        }
292
        
293
        public static void sleep(long millis, long nanos) {
294
                getInstance().sleep(millis, nanos);
295
        }
296
        
297
        public void setSampleRate(int millis) {
298
                getInstance().rate = millis;
299
        }
300
        
301
        
302
        public void addEventListener(GPSEventListener l) {
303
                getInstance().eventListeners.add(l);
304
        }
305
        
306
        private void fireEvents() {
307
                Iterator it = getInstance().eventListeners.iterator();
308
                while (getInstance().eventsEnabled && it.hasNext()) {
309
                        GPSEventListener l = (GPSEventListener) it.next();
310
                        if (System.currentTimeMillis() - getInstance().lastSampleTime  >= getInstance().rate ) {
311
                                Iterator i = getInstance().register.keySet().iterator();
312
                                while (i.hasNext()) {
313
                                        NMEASentence aux = (NMEASentence) getInstance().register.get(i.next());
314
                                        if (isCurrent(aux)) {
315
                                                // This is a valid record
316
                                                if (aux instanceof GGASentence) {
317
                                                        GGASentence s = (GGASentence) aux;
318
                                                        {
319
                                                                try {
320
                                                                        bw.write(s.getLongitude() + "," + s.getLatitude()+"\n");
321
                                                                        bw.flush();
322
                                                                } catch (IOException e) {
323
                                                                        // TODO Auto-generated catch block
324
                                                                        e.printStackTrace();
325
                                                                }
326
                                                        }
327
                                                        getInstance().fireLonLatPositionReceived(l, s.getLongitude(), s.getLatitude());
328
                                                        
329
                                                        l.precisionChanged(-1, s.getHDOP(), -1);
330
                                                        l.signalQualityChanged(0, s.getSatelliteCount(), s.getQualityStatus());
331
                                                        l.altitudeChanged(s.getAltitude());
332
                                                } else if (aux instanceof GSASentence) {
333
                                                        GSASentence s = (GSASentence) aux;
334
                                                        float[] dissolutions = s.getPrecisionDisolutions();
335
                                                        l.precisionChanged(dissolutions[0], dissolutions[1], dissolutions[2]);
336
                                                        s.getUsedSatellites();
337
                                                } else if (aux instanceof RMCSentence) {
338
                                                        l.unhandledMessage(aux.toString());
339
                                                } else if (aux instanceof VTGSentence) {
340
                                                        VTGSentence s = (VTGSentence) aux;
341
                                                        l.speedChanged(s.getSpeed(), s.getCourse());
342
                                                } else {
343
                                                        l.unhandledMessage(aux.toString());
344
                                                }
345
                                        } else {
346
                                                // This record is too old.
347
                                                getInstance().register.remove(aux);
348
                                        }
349
                                }
350

    
351
                                getInstance().lastSampleTime = System.currentTimeMillis();
352
                        }
353
                }
354
        }
355
        
356
        private void fireLonLatPositionReceived(GPSEventListener listener, double longitude, double latitude) {
357
                getInstance().currentPos = new Point2D.Double(longitude, latitude);
358
                listener.newLonLatPositionReceived(longitude - lonOffset, latitude - latOffset);
359
        }
360

    
361
        private boolean isCurrent(NMEASentence n) {
362
                return System.currentTimeMillis() - n.getTime() < timeOut;
363
        }
364
        
365
        /**
366
         * Silences the event firing. To resume the event firing just call <b>start()</b> method.  
367
         */
368
        public void silence() {
369
                getInstance().eventsEnabled = false;
370
        }
371
        
372
        public static void main(String[] args) {
373
                if (args.length < 4) {
374
                        System.out.print("GPSReader port portSpeed\n");
375
                        System.exit(-1);
376
                }
377
                Enumeration portList = CommPortIdentifier.getPortIdentifiers();
378
                while (portList.hasMoreElements()) {
379
                        CommPortIdentifier myPortId = (CommPortIdentifier) portList.nextElement();
380
                        if (myPortId.getPortType() == CommPortIdentifier.PORT_SERIAL) {
381
                                if (myPortId.getName().equals(args[0])) {
382
                                        try {
383
                                                GPSDriver driver = GPSDriver.getInstance();
384
                                                driver.setPort(myPortId, Integer.parseInt(args[1]), SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
385
                                                driver.setSampleRate(100);
386
                                                driver.addEventListener(new GPSEventListener() {
387
                                                        public void unhandledMessage(String msg) {
388
                                                                System.out.println("UNHANDLED: "+msg);
389
                                                        }
390

    
391
                                                        public void connectionLost() {
392
                                                                System.out.println("CONNECTION LOST");        
393
                                                        }
394

    
395
                                                        public void connectionEstablished() {
396
                                                                System.out.println("CONNECTION ESTABLISHED");
397
                                                        }
398

    
399
                                                        public void newLonLatPositionReceived(double lon, double lat) {
400
                                                                System.out.println("NEW LONLAT POSITION RECEIVED: ("+lon+", "+lat+")");
401
                                                        }
402

    
403
                                                        public void signalQualityChanged(float level, int satellites, String qualityStatus) {
404
                                                                System.out.println("NEW SIGNAL LEVEL: "+level+" ("+satellites+" satellites in view)");
405
                                                        }
406

    
407
                                                        public void speedChanged(float speed, short course) {
408
                                                                System.out.println("SPEED/COURSE CHANGED: ( "+speed+" Km/h, "+course+" degrees)");
409
                                                        }
410

    
411
                                                        public void estimatedPosErrorChanged(double e) {
412
                                                                System.out.println("ESTIMATED POSITION ERROR CHANGED: "+e);
413
                                                        }
414

    
415
                                                        public void altitudeChanged(float height) {
416
                                                                System.out.println("HEIGHT CHANGED: "+height);
417
                                                        }
418

    
419
                                                        public void precisionChanged(float pDop, float hDop, float vDop) {
420
                                                                System.out.println("PRECISION CHANGED: "+pDop+", "+hDop+", "+vDop+")");
421
                                                        }
422
                                                        
423
                                                });
424
                                                driver.connect();
425
                                        } catch (PortInUseException e) {
426
                                                System.err.println("Port busy");
427
                                        }
428
                                        
429
                                }
430
                        }
431
                }
432
        }
433

    
434
        
435
        public void close() {
436
                stop();
437
                if (getInstance().serialPort != null) {
438
                        getInstance().serialPort.notifyOnDataAvailable(false);
439
                        getInstance().serialPort.removeEventListener();
440
                        if (getInstance().inputStream != null) {
441
                                try {
442
                                        getInstance().inputStream.close();
443
                                }
444
                                catch (IOException e) {}
445
                        }
446
                        if (getInstance().outputStream != null) {
447
                                try {
448
                                        getInstance().outputStream.close();
449
                                        getInstance().outputStream = null;
450
                                }
451
                                catch (IOException e) {}
452
                        }
453
                        getInstance().serialPort.close();
454
                        getInstance().serialPort = null;
455
                }
456
                getInstance().connected = false;
457
                Iterator it = getInstance().eventListeners.iterator();
458
                while (getInstance().eventsEnabled && it.hasNext()) {
459
                        GPSEventListener l = (GPSEventListener) it.next();
460
                        l.connectionLost();
461
                }
462
                instance = null;
463
                
464
        }
465
        
466
        /**
467
         * Sets the offset of the GPS receiver. By default it is 0, but sometimes it
468
         * is useful to calibrate it.
469
         * 
470
         * @param lonOffset
471
         * @param latOffset
472
         * @throws GPSReceiverException 
473
         */
474
        public void setPosOffset(double lonOffset, double latOffset) {
475
                        this.lonOffset = lonOffset;
476
                        this.latOffset = latOffset;
477
        }
478
        
479
        public Point2D getCurrentPosition() {
480
                return currentPos;
481
        }
482

    
483
        public int getSampleRate() {
484
                return rate;
485
        }
486
}