package com.nutiteq.location.providers;
import java.io.IOException;
import java.io.InputStream;
import com.nutiteq.components.WgsPoint;
import com.nutiteq.location.LocationListener;
import com.nutiteq.location.LocationMarker;
import com.nutiteq.location.LocationSource;
import com.nutiteq.log.Log;
import com.nutiteq.utils.IOUtils;
import com.nutiteq.utils.Utils;
/**
* Provider reading NMEA data from given connection source.
*/
public class BluetoothProvider extends Thread implements LocationSource {
private static final String RMC_SENTANCE_START = "$GPRMC";
private static final String RMC_STATUS_ACTIVE = "A";
private boolean running;
private final String url;
private InputStream is;
private boolean connected;
private WgsPoint location;
private LocationMarker marker;
private final LocationDataConnectionProvider connectionProvider;
private LocationDataConnection connection;
private boolean firstTry = true;
private LocationListener[] listeners = new LocationListener[0];
/**
* Create provider
*
* @param connectionProvider
* object for connection handling
* @param url
* url for connection
*/
public BluetoothProvider(final LocationDataConnectionProvider connectionProvider, final String url) {
this.connectionProvider = connectionProvider;
this.url = url;
}
public WgsPoint getLocation() {
return location;
}
public int getStatus() {
return connected ? STATUS_CONNECTED : STATUS_CONNECTING;
}
public void run() {
running = true;
while (running) {
connect();
while (running && connected) {
final String line = readLine();
if (line.length() == 0) {
disconnect();
continue;
}
Log.debug(line);
parseData(line);
for (int i = 0; i < listeners.length; i++) {
listeners[i].setLocation(location);
}
sleepSomeTime(10);
}
sleepSomeTime(5000);
}
Log.debug("BT done");
}
private void parseData(final String line) {
if (line.length() == 0) {
return;
}
final String[] split = Utils.split(line, ",");
if (RMC_SENTANCE_START.equals(split[0]) && RMC_STATUS_ACTIVE.equals(split[2])) {
final double lat = Utils.parseDecimalDegree(split[3], split[4]);
final double lon = Utils.parseDecimalDegree(split[5], split[6]);
location = new WgsPoint(lon, lat);
}
}
private void sleepSomeTime(final long howLong) {
if (!running) {
return;
}
synchronized (this) {
try {
Log.debug("" + howLong);
wait(howLong);
} catch (final InterruptedException ignore) {
}
}
}
private String readLine() {
try {
final StringBuffer sb = new StringBuffer();
int c = 0;
for (int i = 0;; i++) {
c = is.read();
if (c == -1 || c == '\0' || c == '\n') {
break;
}
if (c != '\r') {
sb.append((char) c);
}
}
return sb.toString();
} catch (final Exception ex) {
Log.error("Error receiving data");
Log.printStackTrace(ex);
// disconnect if an error occurs
disconnect();
return "";
}
}
public void disconnect() {
Log.info("BT disconnect");
IOUtils.closeStream(is);
connection.disconnect();
connected = false;
}
private void connect() {
Log.info("Connect");
try {
connection = connectionProvider.openConnection(url);
is = connection.openInputStream();
connected = true;
} catch (final IOException e) {
Log.error("BT connect " + e.getMessage());
Log.printStackTrace(e);
if (firstTry) {
quit();
}
}
firstTry = false;
Log.info("End connect");
}
public LocationMarker getLocationMarker() {
return marker;
}
public void quit() {
if (!running) {
return;
}
running = false;
disconnect();
marker.quit();
synchronized (this) {
notify();
}
}
public void setLocationMarker(final LocationMarker marker) {
this.marker = marker;
marker.setLocationSource(this);
addLocationListener(marker);
}
public void addLocationListener(final LocationListener listener) {
final LocationListener[] newListeners = new LocationListener[listeners.length + 1];
System.arraycopy(listeners, 0, newListeners, 0, listeners.length);
newListeners[listeners.length] = listener;
listeners = newListeners;
}
}