diff --git a/app/build.gradle b/app/build.gradle index b2cc588..0b1ebf4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,15 +1,16 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion '26.0.3' + compileSdkVersion 29 + buildToolsVersion '29.0.2' defaultConfig { applicationId "de.fhws.indoor.sensorreadout" - minSdkVersion 21 + minSdkVersion 19 targetSdkVersion 23 versionCode 1 versionName "1.0" + multiDexEnabled true } buildTypes { release { diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java index 03e182f..e8e6cb5 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java @@ -35,12 +35,12 @@ import java.util.Set; import de.fhws.indoor.sensorreadout.sensors.GpsNew; import de.fhws.indoor.sensorreadout.sensors.GroundTruth; import de.fhws.indoor.sensorreadout.sensors.Logger; +import de.fhws.indoor.sensorreadout.sensors.LoggerRAM; import de.fhws.indoor.sensorreadout.sensors.PedestrianActivity; import de.fhws.indoor.sensorreadout.sensors.PedestrianActivityButton; import de.fhws.indoor.sensorreadout.sensors.PhoneSensors; import de.fhws.indoor.sensorreadout.sensors.WiFi; import de.fhws.indoor.sensorreadout.sensors.iBeacon; -import de.fhws.indoor.sensorreadout.sensors.iBeaconOld; import de.fhws.indoor.sensorreadout.sensors.mySensor; import de.fhws.indoor.sensorreadout.sensors.SensorType; @@ -53,7 +53,8 @@ public class MainActivity extends Activity { MediaPlayer mpFailure; private final ArrayList sensors = new ArrayList(); - private final Logger logger = new Logger(this); + //private final Logger logger = new Logger(this); + private final LoggerRAM logger = new LoggerRAM(this); private Button btnStart; private Button btnStop; private Button btnGround; @@ -250,29 +251,39 @@ public class MainActivity extends Activity { logger.addCSV(id, timestamp, csv); - runOnUiThread(new Runnable() { - @Override public void run() { - if (id == SensorType.WIFI) { - final TextView txt = (TextView) findViewById(R.id.txtWifi); - txt.setText( ((++loadCounterWifi % 2) == 0) ? "wi" : "WI"); - } else if (id == SensorType.IBEACON){ - final TextView txt = (TextView) findViewById(R.id.txtBeacon); - txt.setText( ((++loadCounterBeacon % 2) == 0) ? "ib" : "IB"); - } else if (id == SensorType.GPS){ - final TextView txt = (TextView) findViewById(R.id.txtGPS); - txt.setText( ((++loadCounterGPS % 2) == 0) ? "gps" : "GPS");} + // update UI for WIFI/BEACON/GPS + if (id == SensorType.WIFI || id == SensorType.IBEACON || id == SensorType.GPS) { + runOnUiThread(new Runnable() { + @Override + public void run() { - // dump buffer stats every x entries - if (++loadCounterAny % 250 == 0) { + if (id == SensorType.WIFI) { + final TextView txt = (TextView) findViewById(R.id.txtWifi); + txt.setText(((++loadCounterWifi % 2) == 0) ? "wi" : "WI"); + } else if (id == SensorType.IBEACON) { + final TextView txt = (TextView) findViewById(R.id.txtBeacon); + txt.setText(((++loadCounterBeacon % 2) == 0) ? "ib" : "IB"); + } else if (id == SensorType.GPS) { + final TextView txt = (TextView) findViewById(R.id.txtGPS); + txt.setText(((++loadCounterGPS % 2) == 0) ? "gps" : "GPS"); + } + } + }); + } + + // dump buffer stats every x entries + if (++loadCounterAny % 250 == 0) { + runOnUiThread(new Runnable() { + @Override + public void run() { final TextView txt = (TextView) findViewById(R.id.txtBuffer); final float elapsedMinutes = (timestamp - logger.getStartTS()) / 1000.0f / 1000.0f / 1000.0f / 60.0f; final int kBPerMin = (int) (logger.getTotalSize() / 1024.0f / elapsedMinutes); - txt.setText( (logger.getCurrentBufferSize() / 1024) + "k, " + logger.getNumEntries() + ", " + kBPerMin + "kB/m"); + txt.setText((logger.getCurrentBufferSize() / 1024) + "k, " + logger.getNumEntries() + ", " + kBPerMin + "kB/m"); } - - } - }); + }); + } } @@ -439,7 +450,7 @@ public class MainActivity extends Activity { }); } if(activeSensors.contains("WIFI")) { - // logo wifi using sensor number 8 + // log wifi using sensor number 8 final WiFi wifi = new WiFi(this); sensors.add(wifi); wifi.setListener(new mySensor.SensorListener() { @@ -461,15 +472,18 @@ public class MainActivity extends Activity { final mySensor beacon; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { beacon = new iBeacon(this); - } else{ - beacon = new iBeaconOld(this); + } else { + beacon = null; + //beacon = new iBeaconOld(this); } - sensors.add(beacon); - beacon.setListener(new mySensor.SensorListener() { - @Override public void onData(final long timestamp, final String csv) { add(SensorType.IBEACON, csv, timestamp); } - @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } - }); + if (beacon != null) { + sensors.add(beacon); + beacon.setListener(new mySensor.SensorListener() { + @Override public void onData(final long timestamp, final String csv) { add(SensorType.IBEACON, csv, timestamp); } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } + }); + } } } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java index b73da7a..264f1a8 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java @@ -166,7 +166,7 @@ public final class Logger { @Override public int compareTo(@NonNull LogEntry another) { - return (int)(timestamp - another.timestamp); + return (timestamp < another.timestamp) ? (-1) : (+1); } } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java new file mode 100644 index 0000000..417b298 --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java @@ -0,0 +1,171 @@ +package de.fhws.indoor.sensorreadout.sensors; + +import android.content.Context; +import android.os.SystemClock; +import android.support.annotation.NonNull; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Collections; + +/** + * log sensor data to RAM + * only flush to file when finished + */ +public final class LoggerRAM { + + public static final long BEGINNING_TS = -1; + + + private StringBuilder stringBuilder = new StringBuilder(); + private File file; + private FileOutputStream fos; + private Context context; + + private boolean addingStopped = false; + private int entries = 0; + private int sizeTotal = 0; + private int currentSize = 0; + + private ArrayList buffer = new ArrayList<>(); + + /** timestamp of logging start. all entries are relative to this one */ + private long startTS = 0; + + public LoggerRAM(Context context) { + this.context = context; + } + + /** start logging (into RAM) */ + public final void start() { + + // start empty + stringBuilder.setLength(0); + entries = 0; + sizeTotal = 0; + currentSize = 0; + buffer.clear(); + addingStopped = false; + + // starting timestamp + startTS = SystemClock.elapsedRealtimeNanos(); + + // open the output-file immeditaly (to get permission errors) + // but do NOT yet write anything to the file + final DataFolder folder = new DataFolder(context, "sensorOutFiles"); + file = new File(folder.getFolder(), startTS + ".csv"); + + try { + fos = new FileOutputStream(file); + Log.d("logger", "will write to: " + file.toString()); + } catch (final Exception e) { + throw new MyException("error while opening log-file", e); + } + + } + + /** stop logging and flush RAM-data to the flash-chip */ + public final void stop() { + + addingStopped = true; + + synchronized (buffer) { + + // sort by TS (ensure strict ordering) + Collections.sort(buffer); + + // export each entry + for (LogEntry e : buffer) { + try { + fos.write(e.csv.getBytes()); + } catch (final Exception ex) { + ex.printStackTrace();; + } + } + + // done + buffer.clear(); + + } + + // done + close(); + + } + + public File getFile() { + return file; + } + + public int getCurrentBufferSize() {return currentSize;} + public int getTotalSize() {return sizeTotal;} + + public int getNumEntries() {return entries;} + + /** add a new CSV entry for the given sensor number to the internal buffer */ + public final void addCSV(final SensorType sensorNr, final long timestamp, final String csv) { + + if (addingStopped) {return;} + + final long relTS = (timestamp == BEGINNING_TS) ? 0 : (timestamp - startTS); + if(relTS >= 0) { // drop pre startTS logs (at the beginning, sensors sometimes deliver old values) + + stringBuilder.setLength(0); + stringBuilder.append(relTS); // relative timestamp (uses less space) + stringBuilder.append(';'); + stringBuilder.append(sensorNr.id()); + stringBuilder.append(';'); + stringBuilder.append(csv); + stringBuilder.append('\n'); + ++entries; + LogEntry logEntry = new LogEntry(relTS, stringBuilder.toString()); + sizeTotal += logEntry.csv.length(); + currentSize += logEntry.csv.length(); + + synchronized (buffer) { + buffer.add(logEntry); + } + + } + + } + + private final void close() { + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while writing log-file", e); + } + } + + public final long getStartTS() { + return startTS; + } + + int cnt = 0; + private final void debug(boolean force) { + if (++cnt % 1000 == 0 || force) { + Log.d("buffer", "size: " + buffer.size() + " lines"); + } + } + + + + private static class LogEntry implements Comparable { + public long timestamp; + public String csv; + + public LogEntry(long timestamp, String csv) { + this.timestamp = timestamp; + this.csv = csv; + } + + @Override + public int compareTo(@NonNull LogEntry another) { + return (timestamp < another.timestamp) ? (-1) : (+1); + } + } + +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java index b35bb57..e0d57d1 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/WiFi.java @@ -23,6 +23,7 @@ public class WiFi extends mySensor { private final WifiManager wifi; private BroadcastReceiver receiver; private boolean isReceiverRegistered; + private boolean isFirstMeasurement = true; public WiFi(final Activity act) { @@ -40,17 +41,29 @@ public class WiFi extends mySensor { this.receiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - final StringBuilder sb = new StringBuilder(1024); - final List res = wifi.getScanResults(); - long timestamp = System.currentTimeMillis(); - for (final ScanResult sr : res) { - sb.append(Helper.stripMAC(sr.BSSID)).append(';'); - sb.append(sr.frequency).append(';'); - sb.append(sr.level).append(';'); - timestamp = sr.timestamp; - } - if (listener != null && isReceiverRegistered) { - listener.onData(timestamp, sb.toString()); + + // ignore the first measurement + if (isFirstMeasurement) { + isFirstMeasurement = false; + } else { + final StringBuilder sb = new StringBuilder(1024); + final List res = wifi.getScanResults(); + long timestamp = 0; + for (final ScanResult sr : res) { + sb.append(Helper.stripMAC(sr.BSSID)).append(';'); + sb.append(sr.frequency).append(';'); + sb.append(sr.level).append(';'); + + // export with oldest timestamp among all contained measurements + final long nanos = sr.timestamp * 1000; + if (nanos > timestamp) { + timestamp = nanos; + } + + } + if (listener != null && isReceiverRegistered) { + listener.onData(timestamp, sb.toString()); + } } startScan(); //Log.d("wifi", sb.toString()); diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java index ea210f5..9b78cdf 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java @@ -20,7 +20,7 @@ public class iBeacon extends mySensor { private static final int REQUEST_ENABLE_BT = 1; private ScanCallback mLeScanCallback; - /** ctor */ + // ctor public iBeacon(final Activity act) { // sanity check diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java index a7688a2..b190e7a 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeaconOld.java @@ -14,14 +14,14 @@ import android.widget.Toast; /** * Created by toni on 02/06/16. */ - +/* public class iBeaconOld extends mySensor { private BluetoothAdapter bt = null; private static final int REQUEST_ENABLE_BT = 1; private BluetoothAdapter.LeScanCallback mLeScanCallback; - /** ctor */ + // ctor public iBeaconOld(final Activity act) { // sanity check @@ -70,3 +70,4 @@ public class iBeaconOld extends mySensor { } } +*/ diff --git a/build.gradle b/build.gradle index 9d5ad52..5d652f1 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.1.0' + classpath 'com.android.tools.build:gradle:3.4.2' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index b3f6adc..de55c05 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Tue Jun 18 22:08:40 CEST 2019 +#Sun Aug 18 15:19:02 CEST 2019 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip