Refactor LocalServer into downloaders

+basic bt downloader
master
Piotro 2023-07-06 15:34:26 +02:00
rodzic 943ac36c6e
commit ed7d1f897b
9 zmienionych plików z 361 dodań i 103 usunięć

Wyświetl plik

@ -21,6 +21,7 @@ import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicBoolean;
public class BlueAdapter {
private final Activity rootActivity;
@ -159,11 +160,14 @@ public class BlueAdapter {
});
}
class BlockedReaderThread implements Runnable {
public class BlockedReaderThread implements Runnable {
private String lastLine;
private boolean new_line = false;
private Object lock = new Object();
@Override
public void run() {
for (;;) {
while (!Thread.interrupted()) { // kill thread when interruptd
System.out.println("BTHREAD: loop ");
String line = readLine(); // this fails in all cases (device offline, closed transmission error)
if (line == null) {
@ -173,16 +177,44 @@ public class BlueAdapter {
} else {
System.out.println("BTHREAD: received " + line);
}
lastLine = line;
synchronized (lock) {
lastLine = line;
new_line = true;
}
try { Thread.sleep(200); } catch (InterruptedException ignored) {}
}
System.out.println("BTHREAD: exit");
}
public String getLine() {
return lastLine;
String line;
synchronized (lock) {
if (new_line) {
new_line = false;
line = lastLine;
} else {
line = null;
}
}
return line;
}
}
public void close() {
try {
reader.close();
writer.close();
} catch (IOException ignored) {}
try {
bluetoothSocket.close();
} catch (IOException ignored) {}
bluetoothSocket = null;
reader = null;
writer = null;
}
private BlockedReaderThread thread = null;

Wyświetl plik

@ -41,6 +41,8 @@ public class DataCollector implements Runnable {
private SlideshowFragment compassUpdater = null;
private boolean stop = false;
private BlueAdapter ba;
public boolean showSondeSet = false;
public DataCollector(Activity rootActivity) {
@ -52,6 +54,9 @@ public class DataCollector implements Runnable {
locationProvider.startLocationProvider(null);
orientationProvider = new Orientation(rootActivity);
ba = new BlueAdapter(rootActivity);
ba.setDeviceAddress("aaa (98:F4:AB:6D:2B:5E)");
}
public void setMapUpdater(MapUpdater mapUpdater) {
@ -115,7 +120,9 @@ public class DataCollector implements Runnable {
rs_col.setSondeName(sharedPref.getString("rsid",""));
sh_col.setSondeName(sharedPref.getString("shid",""));
lc_col = new LocalServerCollector(sharedPref.getString("lsip",""));
lc_col = new LocalServerCollector();
lc_col.setPipeSource(sharedPref.getString("lsip",""));
rs_col_thread = new Thread(rs_col, "rscol");
sh_col_thread = new Thread(sh_col, "shcol");
@ -142,7 +149,6 @@ public class DataCollector implements Runnable {
Sonde lc_last_sonde = lc_col.getLastSonde();
Sonde sh_last_sonde = sh_col.getLastSonde();
if (lc_last_sonde != null && (rs_last_sonde == null || rs_last_sonde.time <= lc_last_sonde.time))
updatePosition(lc_last_sonde, "LOCAL");
else if (rs_last_sonde != null && (sh_last_sonde == null || sh_last_sonde.time <= rs_last_sonde.time))
@ -244,12 +250,8 @@ public class DataCollector implements Runnable {
void updateStatus() {
long time = new Date().getTime();
int lc = Color.RED;
if (time - lc_col.last_success < 10000) {
lc = Color.YELLOW;
if (time - lc_col.last_decoded < 20000)
lc = Color.GREEN;
}
int lc = lc_col.getStatus() == LocalServerCollector.Status.RED ? Color.RED :
(lc_col.getStatus() == LocalServerCollector.Status.YELLOW ? Color.YELLOW : Color.GREEN);
int scol = (time - sh_col.last_decoded < 60000) ? Color.GREEN : Color.RED;
int rcol = (time - rs_col.last_decoded < 60000) ? Color.GREEN : Color.RED;

Wyświetl plik

@ -14,133 +14,130 @@ import java.util.Date;
import javax.net.ssl.HttpsURLConnection;
import eu.piotro.sondechaser.data.local.LocalServerDownloader;
import eu.piotro.sondechaser.data.local.MySondyDownloader;
import eu.piotro.sondechaser.data.local.PipeServerDownloader;
public class LocalServerCollector implements Runnable {
private final String BASE_URL;
private Sonde lastSonde;
private Sonde prevSonde;
private ArrayList<GeoPoint> track;
private final Object dataLock = new Object();
private ArrayList<GeoPoint> prediction;
private Point pred_point;
public long last_success;
public long last_decoded;
private Status status;
private long last_decoded;
private int terrain_alt = 0;
private volatile boolean stop = false;
public LocalServerCollector(String ip) {
BASE_URL = "http://" + ip + "/";
public LocalServerCollector() {}
private enum Mode {
NONE,
PIPE,
MYSONDY,
}
public enum Status {
RED,
YELLOW,
GREEN,
}
private Mode source;
private PipeServerDownloader pipeDownloader;
private MySondyDownloader mySondyDownloader;
private void disable() {
// pipe downloader does not need disabling
mySondyDownloader.disable();
source = Mode.NONE;
}
public void setPipeSource(String ip) {
disable();
pipeDownloader = new PipeServerDownloader(ip);
source = Mode.PIPE;
}
public void setMySondySource(BlueAdapter blueAdapter) {
disable();
mySondyDownloader = new MySondyDownloader(blueAdapter);
mySondyDownloader.enable();
source = Mode.MYSONDY;
}
@Override
public void run() {
lastSonde = null;
track = new ArrayList<>();
pred_point = null;
prediction = new ArrayList<>();
last_success = 0;
last_decoded = 0;
status = Status.RED;
while (!stop) {
download();
getData();
generatePrediction();
try {
Thread.sleep(2000);
} catch (InterruptedException ignored) {}
boolean ignored = Thread.interrupted();
}
disable();
}
private void downloadData(URL url, SondeParser parser) {
try {
System.err.println(url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
System.err.println(conn.getResponseCode());
if (conn.getResponseCode() == 200) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder resp = new StringBuilder();
for (String line; (line = br.readLine()) != null; resp.append(line));
parser.parse(resp.toString());
last_success = new Date().getTime();
}
private void getData() {
if (source == Mode.NONE) {
status = Status.RED;
return;
}
LocalServerDownloader downloader = (source == Mode.PIPE ? pipeDownloader : mySondyDownloader);
downloader.download();
} finally {
conn.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
prevSonde = lastSonde;
synchronized (dataLock) {
lastSonde = downloader.getLastSonde();
last_decoded = downloader.getLastDecoded();
status = downloader.getStatus();
}
}
private class Parser implements SondeParser {
public void parse(String data) {
try {
JSONObject json = new JSONObject(data);
if (json.length() == 0 || !json.getBoolean("valid")) {
return;
}
Sonde sonde = new Sonde();
float lat = (float)json.getDouble("lat");
float lon = (float)json.getDouble("lon");
sonde.loc = new GeoPoint(lat, lon);
sonde.alt = (int)Math.round(json.getDouble("alt"));
sonde.time = json.getLong("time")*1000;
sonde.vspeed = (float)json.getDouble("vs");
sonde.freq = null;
sonde.sid = null;
System.out.println(sonde.alt);
if (lastSonde != null && sonde.time == lastSonde.time)
return;
if(sonde.time > new Date().getTime() && sonde.time - new Date().getTime() < 600_000) {
// Sonde clocks tend to shift in time
sonde.time = new Date().getTime();
}
if (lastSonde != null) {
float timedev = (sonde.time - lastSonde.time) / 1000.f;
float latdev = (float)(sonde.loc.getLatitude() - lastSonde.loc.getLatitude()) / timedev;
float londev = (float)(sonde.loc.getLongitude() - lastSonde.loc.getLongitude()) / timedev;
float tgalt = terrain_alt;
float nextlat = (float)sonde.loc.getLatitude() + (latdev * ((sonde.alt - tgalt) / (sonde.vspeed * -1)));
float nextlon = (float)sonde.loc.getLongitude() + (londev * ((sonde.alt - tgalt) / (sonde.vspeed * -1)));
synchronized (dataLock) {
pred_point = new Point();
pred_point.point = new GeoPoint(nextlat, nextlon);
pred_point.alt = (int) tgalt;
pred_point.time = 0;
prediction = new ArrayList<>();
prediction.add(sonde.loc);
prediction.add(pred_point.point);
}
}
private void generatePrediction() {
Sonde sonde = lastSonde;
{
Sonde lastSonde = prevSonde; // shadow
if (sonde.time > new Date().getTime() && sonde.time - new Date().getTime() < 600_000) {
// Sonde clocks tend to shift in time
sonde.time = new Date().getTime();
}
if (lastSonde != null) {
float timedev = (sonde.time - lastSonde.time) / 1000.f;
float latdev = (float) (sonde.loc.getLatitude() - lastSonde.loc.getLatitude()) / timedev;
float londev = (float) (sonde.loc.getLongitude() - lastSonde.loc.getLongitude()) / timedev;
float tgalt = terrain_alt;
float nextlat = (float) sonde.loc.getLatitude() + (latdev * ((sonde.alt - tgalt) / (sonde.vspeed * -1)));
float nextlon = (float) sonde.loc.getLongitude() + (londev * ((sonde.alt - tgalt) / (sonde.vspeed * -1)));
synchronized (dataLock) {
System.out.println("localupd");
lastSonde = sonde;
track.add(sonde.loc);
pred_point = new Point();
pred_point.point = new GeoPoint(nextlat, nextlon);
pred_point.alt = (int) tgalt;
pred_point.time = 0;
prediction = new ArrayList<>();
prediction.add(sonde.loc);
prediction.add(pred_point.point);
}
last_decoded = new Date().getTime();
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void download() {
try {
URL url = new URL(BASE_URL + "get");
downloadData(url, new Parser());
} catch (Exception ignored) {}
}
public Sonde getLastSonde() {
synchronized (dataLock) {
return lastSonde;
@ -161,6 +158,14 @@ public class LocalServerCollector implements Runnable {
synchronized (dataLock) {return pred_point;}
}
public Status getStatus() {
return status;
}
public long getLastDecoded() {
return last_decoded;
}
public void updateTerrainAlt(int alt) {
terrain_alt = alt;
}

Wyświetl plik

@ -225,7 +225,7 @@ public class RadiosondyCollector implements Runnable {
//sonde.vspeed = 0;
String time_str = curr.getJSONObject("properties").getString("description");
System.err.println(time_str.substring(11, 11+19));
System.err.println("Radiosondy" + time_str.substring(11, 11+19));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
sonde.time = sdf.parse(time_str.substring(11, 11+19)).getTime();
@ -239,7 +239,6 @@ public class RadiosondyCollector implements Runnable {
for (int i=path.length()-1; i>=0; i-=10) {
JSONArray entry = path.getJSONArray(i);
gps.add(new GeoPoint(entry.getDouble(1), entry.getDouble(0)));
System.out.println(entry.getDouble(0));
}
synchronized (dataLock) {
track = gps;

Wyświetl plik

@ -0,0 +1,15 @@
package eu.piotro.sondechaser.data.local;
import eu.piotro.sondechaser.data.LocalServerCollector;
import eu.piotro.sondechaser.data.Sonde;
public interface LocalServerDownloader {
void download();
Sonde getLastSonde();
long getLastDecoded();
LocalServerCollector.Status getStatus();
void enable();
void disable();
}

Wyświetl plik

@ -0,0 +1,74 @@
package eu.piotro.sondechaser.data.local;
import java.util.Date;
import eu.piotro.sondechaser.data.BlueAdapter;
import eu.piotro.sondechaser.data.LocalServerCollector;
import eu.piotro.sondechaser.data.Sonde;
public class MySondyDownloader implements LocalServerDownloader {
private final BlueAdapter blueAdapter;
private BlueAdapter.BlockedReaderThread bt_runnable;
private Thread bt_thread;
private Sonde lastSonde;
private long last_decoded;
private LocalServerCollector.Status mStatus = LocalServerCollector.Status.RED;
public MySondyDownloader(BlueAdapter blueAdapter) {
this.blueAdapter = blueAdapter;
}
@Override
public void enable() {
disable();
// Address and mode should be configured already in passed object
bt_runnable = blueAdapter.getRunnable();
bt_thread = new Thread(bt_runnable);
bt_thread.start();
}
@Override
public void disable() {
if(bt_thread == null)
return;
bt_thread.interrupt();
blueAdapter.close();
}
@Override
public void download() {
if (!blueAdapter.isConnected())
mStatus = LocalServerCollector.Status.RED;
else
mStatus = LocalServerCollector.Status.YELLOW;
String line = bt_runnable.getLine();
if (line == null)
return;
System.out.println("PARSE" + line);
last_decoded = new Date().getTime();
}
@Override
public Sonde getLastSonde() {
return lastSonde;
}
@Override
public long getLastDecoded() {
return last_decoded;
}
@Override
public LocalServerCollector.Status getStatus() {
return mStatus;
}
}

Wyświetl plik

@ -0,0 +1,125 @@
package eu.piotro.sondechaser.data.local;
import org.json.JSONObject;
import org.osmdroid.util.GeoPoint;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Date;
import eu.piotro.sondechaser.data.LocalServerCollector;
import eu.piotro.sondechaser.data.Sonde;
import eu.piotro.sondechaser.data.SondeParser;
public class PipeServerDownloader implements LocalServerDownloader {
private final String BASE_URL;
public PipeServerDownloader(String ip) {
BASE_URL = "http://" + ip + "/";
}
private long last_received;
private long last_decoded;
private Sonde lastSonde = null;
private LocalServerCollector.Status mStatus = LocalServerCollector.Status.RED;
private void downloadData(URL url, SondeParser parser) {
try {
System.err.println(url);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
try {
System.err.println(conn.getResponseCode());
if (conn.getResponseCode() == 200) {
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder resp = new StringBuilder();
for (String line; (line = br.readLine()) != null; resp.append(line));
parser.parse(resp.toString());
last_received = new Date().getTime();
}
} finally {
conn.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
}
private class Parser implements SondeParser {
public void parse(String data) {
try {
JSONObject json = new JSONObject(data);
if (json.length() == 0 || !json.getBoolean("valid")) {
return;
}
Sonde sonde = new Sonde();
float lat = (float)json.getDouble("lat");
float lon = (float)json.getDouble("lon");
sonde.loc = new GeoPoint(lat, lon);
sonde.alt = (int)Math.round(json.getDouble("alt"));
sonde.time = json.getLong("time")*1000;
sonde.vspeed = (float)json.getDouble("vs");
sonde.freq = null;
sonde.sid = null;
System.out.println("LocalPipeServer" + sonde.time);
if (lastSonde != null && sonde.time != lastSonde.time)
last_decoded = new Date().getTime();
lastSonde = sonde;
} catch (Exception e) {
e.printStackTrace();
}
}
}
private void updateStatus() {
LocalServerCollector.Status lc = LocalServerCollector.Status.RED;
if (new Date().getTime() - last_received < 10000) {
lc = LocalServerCollector.Status.YELLOW;
if (new Date().getTime() - last_decoded < 20000)
lc = LocalServerCollector.Status.GREEN;
}
mStatus = lc;
}
@Override
public void download() {
try {
updateStatus();
URL url = new URL(BASE_URL + "get");
downloadData(url, new Parser());
} catch (Exception ignored) {}
}
@Override
public Sonde getLastSonde() {
return lastSonde;
}
@Override
public long getLastDecoded() {
return last_decoded;
}
@Override
public LocalServerCollector.Status getStatus() {
return mStatus;
}
@Override
public void enable() {}
@Override
public void disable() {}
}

Wyświetl plik

@ -20,6 +20,7 @@ import java.time.Duration;
import eu.piotro.sondechaser.MainActivity;
import eu.piotro.sondechaser.R;
import eu.piotro.sondechaser.data.BlueAdapter;
import eu.piotro.sondechaser.data.RadiosondyCollector;
import eu.piotro.sondechaser.data.SondeHubCollector;
import eu.piotro.sondechaser.databinding.FragmentGalleryBinding;
@ -101,6 +102,10 @@ public class GalleryFragment extends Fragment {
((TextView)v.findViewById(R.id.tfsh)).setText(entry);
return true;
});
// PopupMenu btPopupMenu = new PopupMenu(context, v.findViewById(R.id.set_awake));
// new BlueAdapter(getActivity()).fillMenu(getActivity(), btPopupMenu);
// btPopupMenu.show();
}
@Override

Wyświetl plik

@ -108,4 +108,5 @@
android:text="Keep screen awake"
app:layout_constraintStart_toStartOf="@+id/tfip"
app:layout_constraintTop_toBottomOf="@+id/tfip" />
</androidx.constraintlayout.widget.ConstraintLayout>