/* * XCTrack - XContest Live Tracking client for J2ME devices * Copyright (C) 2009 Petr Chromec <petr@xcontest.org> * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package org.xcontest.xctrack.gps; import java.util.Calendar; import java.util.Vector; import org.xcontest.xctrack.gps.GpsMessage; import org.xcontest.xctrack.util.Log; import org.xcontest.xctrack.util.ValueForm; public abstract class GpsDriver { /// in seconds protected int GPS_POSITION_MAXAGE = 5; private static GpsDriver[] _allDrivers = null; private GpsListener _listener; private long _lastPositionTime; private boolean _hasSignal; public GpsDriver() { _listener = null; _lastPositionTime = -1; _hasSignal = false; } public static GpsDriver[] getAllDrivers() { if (_allDrivers == null) { Vector all = new Vector(); try { Class.forName("javax.microedition.location.LocationProvider"); all.addElement(new LocationApiGps()); } catch(Exception ex){ Log.info("Location API not supported"); } try { Class.forName("javax.bluetooth.LocalDevice"); all.addElement(new BluetoothGps()); } catch(Exception ex){ Log.info("Bluetooth not supported"); } all.addElement(new SerialPortGps()); all.addElement(new CustomNMEAGps()); all.addElement(new DemoGps()); int ndrivers = all.size(); _allDrivers = new GpsDriver[ndrivers]; for (int i = 0; i < ndrivers; i ++) { _allDrivers[i] = (GpsDriver)all.elementAt(i); } } return _allDrivers; } public static GpsDeviceInfo[] scanAllDrivers() throws InterruptedException { GpsDriver[] drivers = getAllDrivers(); GpsDeviceInfo[][] dev = new GpsDeviceInfo[drivers.length][]; int cnt; cnt = 0; for (int i = 0; i < drivers.length; i ++) { dev[i] = drivers[i].scanDevices(); cnt += dev[i].length; } GpsDeviceInfo[] all = new GpsDeviceInfo[cnt]; cnt = 0; for (int i = 0; i < drivers.length; i ++) for (int j = 0; j < dev[i].length; j ++) all[cnt++] = dev[i][j]; return all; } /** * checks the age of last received position, causing calls to signalReached() or signalLost() * @param msg just received message or null */ protected void checkGpsPositionAge(GpsMessage msg) { long now = Calendar.getInstance().getTime().getTime(); if (msg != null && msg.hasPosition) { _lastPositionTime = now; if (!_hasSignal) { signalReached(); _hasSignal = true; } } else if (_lastPositionTime >= 0 && _lastPositionTime + GPS_POSITION_MAXAGE*1000 < now) { if (_hasSignal) { signalLost(); _hasSignal = false; } } } public abstract String getDriverId(); /** returns driver name */ public abstract String getName(); /** Setup the communication thread and try to connect the requested device. Keep retrying on errors, report connection state trough deviceConnected(), deviceDisconnected(), error() */ public abstract void connect(String address); /** Disconnect device */ public abstract void disconnect(); /** returns the list of visible devices */ public abstract GpsDeviceInfo[] scanDevices() throws InterruptedException; public synchronized void setListener(GpsListener l) { _listener = l; } /** Pass the GpsMessage to listeners */ protected synchronized void notifyListeners(GpsMessage msg) { if (_listener != null) _listener.gpsMessage(msg); } /** The gps device is connected */ protected synchronized void deviceConnected() { if (_listener != null) _listener.deviceConnected(); } /** The gps device was disconnected */ protected synchronized void deviceDisconnected() { if (_hasSignal) { _hasSignal = false; signalLost(); } if (_listener != null) _listener.deviceDisconnected(); } /** GPS signal lost */ protected synchronized void signalLost() { if (_listener != null) _listener.signalLost(); } /** GPS on air :-) */ protected synchronized void signalReached() { if (_listener != null) _listener.signalReached(); } /** * * @return true if this driver provides only one (single) device. In such case, function scanDevices() MUST be fast */ public boolean hasSingleDevice() { return false; } /** * * @return true iff the scan for devices is fast at all occasions. false for bluetooth :) */ public boolean hasFastScan() { return true; } public boolean isForDebugModeOnly() { return false; } /** * to be overriden by drivers, which have custom user interface to ask for device * * @param old last chosen device from the same driver or null * * @return form for asking user gps, or null for standard [scan]->[device menu] process * * @see NMEAGps */ public ValueForm askDevice(GpsDeviceInfo old) { return null; } }