Merge mozilla-central and tracemonkey. (a=blockers)
[mozilla-central.git] / dom / system / GPSDGeolocationProvider.js
blob9392f94f8952440cad43964e0c73e5af00d80034
1 /* ***** BEGIN LICENSE BLOCK *****
2  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Mozilla Public License Version
5  * 1.1 (the "License"); you may not use this file except in compliance with
6  * the License. You may obtain a copy of the License at
7  * http://www.mozilla.org/MPL/
8  *
9  * Software distributed under the License is distributed on an "AS IS" basis,
10  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11  * for the specific language governing rights and limitations under the
12  * License.
13  *
14  * The Original Code is Geolocation.
15  *
16  * The Initial Developer of the Original Code is Mozilla Foundation
17  * Portions created by the Initial Developer are Copyright (C) 2008
18  * the Initial Developer. All Rights Reserved.
19  *
20  * Contributor(s):
21  *  Martin McNickle <mmcnickle@gmail.com>
22  *
23  * Based on static_geolocation_provider.js by:
24  *  Doug Turner <dougt@meer.net>
25  *
26  *
27  * Alternatively, the contents of this file may be used under the terms of
28  * either the GNU General Public License Version 2 or later (the "GPL"), or
29  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30  * in which case the provisions of the GPL or the LGPL are applicable instead
31  * of those above. If you wish to allow use of your version of this file only
32  * under the terms of either the GPL or the LGPL, and not to allow others to
33  * use your version of this file under the terms of the MPL, indicate your
34  * decision by deleting the provisions above and replace them with the notice
35  * and other provisions required by the GPL or the LGPL. If you do not delete
36  * the provisions above, a recipient may use your version of this file under
37  * the terms of any one of the MPL, the GPL or the LGPL.
38  *
39  * ***** END LICENSE BLOCK ***** */
41 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
43 const Ci = Components.interfaces;
44 const Cc = Components.classes;
46 var gLoggingEnabled = false;
48 function LOG(aMsg) {
49   if (gLoggingEnabled)
50   {
51     aMsg = ("*** GPSD GEO: " + aMsg);
52     Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
53     dump(aMsg);
54   }
57 function GeoPositionCoordsObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed) {
59   this.latitude = latitude;
60   this.longitude = longitude;
61   this.altitude = altitude;
62   this.accuracy = accuracy;
63   this.altitudeAccuracy = altitudeAccuracy;
64   this.heading = heading;
65   this.speed = speed;
69 GeoPositionCoordsObject.prototype = {
71   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo]),
72   
73   // Class Info is required to be able to pass objects back into the DOM.
74   getInterfaces: function(countRef) {
75     var interfaces = [Ci.nsIDOMGeoPositionCoords, Ci.nsIClassInfo, Ci.nsISupports];
76     countRef.value = interfaces.length;
77     return interfaces;
78   },
79   
80   getHelperForLanguage: function(language) null,
81   contractID: null,
82   classDescription: "Geoposition Coordinate Object",
83   classID: null,
84   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
85   flags: Ci.nsIClassInfo.DOM_OBJECT,
87   latitude: null,
88   longitude: null,
89   altitude: null,
90   accuracy: null,
91   altitudeAccuracy: null,
92   heading: null,
93   speed: null,
97 function GeoPositionObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed, timestamp) {
98   this.coords = new GeoPositionCoordsObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed);
99   this.timestamp = timestamp;
102 GeoPositionObject.prototype = {
104   QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition, Ci.nsIClassInfo]),
106   // Class Info is required to be able to pass objects back into the DOM.
107   getInterfaces: function(countRef) {
108     var interfaces = [Ci.nsIDOMGeoPosition, Ci.nsIClassInfo, Ci.nsISupports];
109     countRef.value = interfaces.length;
110     return interfaces;
111   },
113   getHelperForLanguage: function(language) null,
114   contractID: null,
115   classDescription: "Geoposition Object",
116   classID: null,
117   implementationLanguage: Ci.nsIProgrammingLanguage.JAVASCRIPT,
118   flags: Ci.nsIClassInfo.DOM_OBJECT,
120   coords: null,
121   timestamp: null,
125 function GPSDProvider() {
126   this.prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).QueryInterface(Ci.nsIPrefService);
128   try {
129     gLoggingEnabled = this.prefService.getBoolPref("geo.gpsd.logging.enabled");
130   } catch (e) {}
133 GPSDProvider.prototype = {
134   
135   QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationProvider]),
136   
137   classID: Components.ID("{0A3BE523-0F2A-32CC-CCD8-1E5986D5A79D}"),
138   
139   prefService: null,
141   transport: null,
142   outputStream: null,
143   inputStream: null,
144   
145   startup: function() {
147     LOG("startup called\n");
148     var socketTransportService = Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci.nsISocketTransportService);
149     
150     var hostIPAddr = "127.0.0.1";
151     var hostPort = "2947";
153     try {
154       hostIPAddr = this.prefService.getCharPref("geo.gpsd.host.ipaddr");
155     } catch (e) {}
157     try {
158       hostPort = this.prefService.getCharPref("geo.gpsd.host.port");
159     } catch (e) {}
161     LOG("Host info: " + hostIPAddr + ":" + hostPort + "\n");
163     this.transport = socketTransportService.createTransport(null, 0, hostIPAddr, hostPort, null);
164     
165     // Alright to open streams here as they are non-blocking by default
166     this.outputStream = this.transport.openOutputStream(0,0,0);
167     this.inputStream = this.transport.openInputStream(0,0,0);
169   },
170   
171   shutdown: function() {
172     LOG("shutdown called\n"); 
173     this.outputStream.close();
174     this.inputStream.close();
175     this.transport.close(Components.results.NS_OK);
176   },
177   
178   watch: function(c) {
179     LOG("watch called\n");    
180     try {
181         // Turn GPSD buffer on, results in smoother data points which I think we want.
182         // Required due to the way that different data arrives in different NMEA sentences.
183         var bufferOption = "J=1\n";
184         this.outputStream.write(bufferOption, bufferOption.length);
185         
186         // Go into "watcher" mode
187         var mode = "w\n";
188         this.outputStream.write(mode, mode.length);
189     } catch (e) { return; }
191     var dataListener = {
192       onStartRequest: function(request, context) {},
193       onStopRequest: function(request, context, status) {},
194       onDataAvailable: function(request, context, inputStream, offset, count) {
195     
196         var sInputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
197         sInputStream.init(inputStream);
199         var s = sInputStream.read(count);
200         
201         var response = s.split('=');
202         
203         var header = response[0];
204         var info = response[1];
205         
206         // is this location information?
207         if (header != 'GPSD,O') {
208           // don't do anything
209           return;
210         }
211         
212         // is there a fix?
213         if (info == '?') {
214           // don't do anything
215           return;
216         }
217     
218         // get the info from the string
219         var fields = info.split(' ');
220         
221         // we'll only use RMC data as it seems to make sense
222         if (fields[0] != 'RMC') {
223           return;
224         }
226         LOG("Got info: " + info);
228         for (var i = 0; i < fields.length; i++) {
229           if (fields[i] == '?') {
230             fields[i] = null;
231           }
232         }
233         
234         var timestamp = fields[1]; // UTC
235         var timeError = fields[2]; // seconds
236         var latitude = fields[3]; // degrees
237         var longitude = fields[4]; // degrees
238         var altitude = fields[5]; // meters
239         var horizontalError = fields[6]; // meters
240         var verticalError = fields[7]; // meters
241         var course = fields[8]; // degrees;
242         var speed = fields[9]; // meters/sec maybe knots depending on GPSD version TODO: figure this out
243         
244         var geoPos = new GeoPositionObject(latitude, longitude, altitude, horizontalError, verticalError, course, speed, timestamp);
245         
246         c.update(geoPos);
247     
248       }
249       
250     };
251     
252     var pump = Cc["@mozilla.org/network/input-stream-pump;1"].createInstance(Ci.nsIInputStreamPump);
253     pump.init(this.inputStream, -1, -1, 0, 0, false);
254     pump.asyncRead(dataListener, null);
256   },
257   
260 var NSGetFactory = XPCOMUtils.generateNSGetFactory([GPSDProvider]);