📄 bluetoothgps.java
字号:
package org.j4me.bluetoothgps;
import java.io.*;
import javax.microedition.io.*;
import org.j4me.logging.*;
import org.j4me.util.*;
/**
* Main class for communication with GPS receiver. Use this class to access GPS
* receiver from other classes.
*/
class BluetoothGPS implements Runnable {
/**
* The timeout value for Bluetooth connections in milliseconds.
* Since this tries to connect on 10 Bluetooth channels, the
* total timeout for connecting is 10x this number.
* <p>
* The emulator's default timeout is 10,000 ms.
*/
private static final short BLUETOOTH_TIMEOUT = 3000;
/**
* Time in ms to wait until resume to receive.
*/
private static final short BREAK = 500;
/**
* Wait after calling disconnect
*/
private static final short DISCONNECT_WAIT = 1000;
/**
* Time in ms to sleep before each read. This seems to solve the problem or
* read hangs.
*/
public static final short SLEEP_BEFORE_READ = 100;
/**
* How long to wait before we just kill the read. We add the sleep value
* since this sleep is performed before every read and we start the timer
* before the pre-read sleep.
*/
public static final short READ_TIMEOUT = SLEEP_BEFORE_READ + 1000;
/**
* How long to wait to initialize the bluetooth connection
*/
public static final short BLUETOOTH_CONNECTION_INIT_SLEEP = 200;
/**
* The number of days since January 1 for the start of a month. This does not
* include leap year days.
*
* @see #convertUTCTime(String, String)
*/
private static final int MONTH_OFFSET[] =
{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
/**
* Connection to bluetooth device.
*/
private StreamConnection connection;
/**
* The input stream from the GPS device. Location data is received through it.
*/
private InputStream inputStream;
/**
* The output stream to the GPS device. Configuration commands are sent through it.
*/
private OutputStream outputStream;
/**
* Receiving happens in separate thread.
*/
private Thread runner;
/**
* Flag to indicate that the runner thread should stop
*/
private boolean stop = false;
/**
* URL used to connect to bluetooth device.
*/
private String url;
/**
* Listener to notify of location events. If this is <code>null</code> then
* don't notify anything of location events.
*/
private LocationListener locationListener;
/**
* The source of location information.
*/
private final BluetoothLocationProvider locationProvider;
/**
* The interval, in milliseconds, between calls made to the registered
* <code>LocationListener.locationUpdated</code>.
*
* @see #setLocationListener(LocationListener, BluetoothLocationProvider)
*/
private long locationUpdateInterval;
/**
* The system time for when <code>LocationListener.locationUpdated</code>
* was last raised.
*
* @see #locationUpdateInterval
*/
private long lastLocationUpdateTime;
/**
* The last <code>Location</code> obtained from the GPS. This is the provider's
* best guess about the current location. It is usually less than a second old.
*/
private Location location;
/**
* Creates new receiver. Does not start automatically, use start() instead.
*
* @param url -
* URL of bluetooth device to connect to.
*/
public BluetoothGPS(BluetoothLocationProvider provider, String url) {
this.locationProvider = provider;
this.url = url;
}
/**
* @return The last <code>Location</code> obtained from the GPS or <code>null</code>
* if no location has yet been obtained.
*/
public Location getLastKnownLocation ()
{
return location;
}
/**
* Establishes a bluetooth serial connection (specified in GPS_BT_URL) and
* opens an input stream.
*
* @see #isConnected()
* @see #disconnect()
*
* @throws ConnectionNotFoundException - If the target of the name cannot be found, or if the requested protocol type is not supported.
* @throws IOException - If error occurs while establishing bluetooth connection or opening input stream.
* @throws SecurityException - May be thrown if access to the protocol handler is prohibited.
*/
private synchronized void connect()
throws ConnectionNotFoundException, IOException, SecurityException {
if (!isConnected()) {
// Connect to the GPS device.
Log.info("Connecting to Bluetooth device at " + url);
connection = (StreamConnection) ConnectorHelper.open(
url, Connector.READ_WRITE, BLUETOOTH_TIMEOUT );
Log.debug("Bluetooth connection established");
// Record the connection.
configureBluetoothGPSSettings(connection);
inputStream = connection.openInputStream();
outputStream = connection.openOutputStream();
}
}
/**
* Configure the GPS device.
* <p>
* This sends NMEA input sentences to the Bluetooth GPS device. The type and
* frequency of output sentences sent back from the device should be altered
* such that we do not receive messages we do not care about (to avoid the
* overhead of processing them) and we receive the messages we do care about
* once a second (maximum rate so that if any are corrupt we get our data as
* fast as possible).
* <p>
* On a few devices it is possible to adjust the baud rate. However, this is
* not a good option. It isn't the speed data is transmitted (actually faster
* is better), it is the amount of quality data that comes through.
* <p>
* A good list of the proprietary input sentences is here:
* http://www.gpsinformation.org/dale/nmea.htm
*
* @param connection
* is the connection object to the Bluetooth GPS unit. The
* connection must be {@link Connector#READ} or
* {@link Connector#READ_WRITE}.
*/
private void configureBluetoothGPSSettings(StreamConnection connection)
{
if (outputStream != null) {
try {
// Send SiRF configuration.
// These are specific to the SiRF chipset and are ignored by others.
// They are also ignored if the GPS device is in SiRF mode which it
// should not be.
//
// The sentences are discussed here:
// http://www.gpsinformation.org/dale/nmea.htm#sirf
// http://www.elgps.com/public_ftp/Documentos/SIRF_Protocol.pdf
// They can be tested using the SiRFDemo application:
// http://www.gpspassion.com/forumsen/topic.asp?TOPIC_ID=25575
//
// The Bluetooth modems in SiRF devices do not allow the baud rate
// to be changed. It is usually 38400 or higher.
// The SiRF input sentence that controls output sentences is:
// $PSRF103,05,00,01,01*20
// where
// $PSRF103
// 05 00=GGA
// 01=GLL
// 02=GSA
// 03=GSV
// 04=RMC
// 05=VTG
// ... through 10
// 00 mode, 0=set rate, 1=query
// 01 rate in seconds, 0-255
// 01 checksum 0=no, 1=yes
// *20 checksum
// Send the NMEA sentences we care about every second.
outputStream.write( createSentence("PSRF103,00,00,01,01") ); // GPGGA
outputStream.write( createSentence("PSRF103,02,00,01,01") ); // GPGSA
outputStream.write( createSentence("PSRF103,04,00,01,01") ); // GPRMC
// Disable the remaining sentences.
// This avoids the overhead of receiving them, processing them, and
// throwing them away. They can be very frequent and cause problems
// for slow processors such as on the Motorola SLVR.
// Not all of these are NMEA sentences. Some are SiRF specific
// PSRFTXT sentences which are the most frequent and therefore most
// problematic.
outputStream.write( createSentence("PSRF103,01,00,00,01") ); // GPGLL
outputStream.write( createSentence("PSRF103,03,00,00,01") ); // GPGSV
outputStream.write( createSentence("PSRF103,05,00,00,01") ); // GPVTG
outputStream.write( createSentence("PSRF103,06,00,00,01") ); // GPMSS
outputStream.write( createSentence("PSRF103,07,00,00,01") ); // ? (Untested but might be the PSRFTXT we turn off)
outputStream.write( createSentence("PSRF103,08,00,00,01") ); // ? (Untested but might be the PSRFTXT we turn off)
outputStream.write( createSentence("PSRF103,09,00,00,01") ); // GPZDA
outputStream.write( createSentence("PSRF103,10,00,00,01") ); // ? (Untested but might be the PSRFTXT we turn off)
// Send Garmin configuration.
// Garmin device programming (see section 3.1.5)
// http://www.garmin.com/manuals/GPS10_TechnicalSpecifications.pdf
//
// Output sentence enable/disable (PGRMO). The format is:
// $PGRMO,<1>,<2>*hh\r\n
// where
// <1> Target sentence description (e.g. GPGSV)
// <2> Mode where:
// 0 = disable specific sentence
// 1 = enable specific sentence
// 2 = disable all output sentences
// 3 = enable all output sentences (except GPALM)
// 4 = restore factory default output sentences
outputStream.write( createSentence("PGRMO,,2") ); // Turn off all sentences
outputStream.write( createSentence("PGRMO,GPGGA,1") ); // Turn on GPGGA
outputStream.write( createSentence("PGRMO,GPGSA,1") ); // Turn on GPGSA
outputStream.write( createSentence("PGRMO,GPRMC,1") ); // Turn on GPRMC
// Note the following doesn't work. The iBlue is apparently locked
// at the factory presets according to a note on a discussion board.
//
// Send Martech (MTK) configuration. It is the chipset used in the i-Blue 747.
// MTK is produced by Transystem, a company in Taiwan. It is a chipset
// comparable to the SiRF III. See the programming guide:
// http://www.transystem.com.tw/driver_manual/EB-230-Data-Sheet-V1.2.pdf
//
// Output sentence to enable frequency of input sentences is:
// $PMTK314,<0>,...,<18>*hh\r\n
// where each field
// 0=off, 1=every second, 2=every two seconds, etc.
// and the field numbers are
// 0 NMEA_SEN_GLL, // GPGLL interval - Geographic Position - Latitude longitude
// 1 NMEA_SEN_RMC, // GPRMC interval - Recommended Min. specific GNSS sentence
// 2 NMEA_SEN_VTG, // GPVTG interval - Course Over Ground and Ground Speed
// 3 NMEA_SEN_GGA, // GPGGA interval - GPS Fix Data
// 4 NMEA_SEN_GSA, // GPGSA interval - GNSS DOPS and Active Satellites
// 5 NMEA_SEN_GSV, // GPGSV interval - GNSS Satellites in View
// 6 NMEA_SEN_GRS, // GPGRS interval - GNSS Range Residuals
// 7 NMEA_SEN_GST, // GPGST interval - GNSS Pseudorange Error Statistics
// 13 NMEA_SEN_MALM, // PMTKALM interval - GPS almanac information
// 14 NMEA_SEN_MEPH, // PMTKEPH interval - GPS ephemeris information
// 15 NMEA_SEN_MDGP, // PMTKDGP interval - GPS differential correction information
// 16 NMEA_SEN_MDBG, // PMTKDBG interval
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -