diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index df31f89..249edd7 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/caches/build_file_checksums.ser.orig b/.idea/caches/build_file_checksums.ser.orig new file mode 100644 index 0000000..c0a1d75 Binary files /dev/null and b/.idea/caches/build_file_checksums.ser.orig differ diff --git a/.idea/caches/gradle_models.ser b/.idea/caches/gradle_models.ser new file mode 100644 index 0000000..f334320 Binary files /dev/null and b/.idea/caches/gradle_models.ser differ diff --git a/.idea/modules.xml b/.idea/modules.xml index 55d94cb..9a8c334 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ - + - + \ No newline at end of file diff --git a/.idea/modules.xml.orig b/.idea/modules.xml.orig new file mode 100644 index 0000000..a967c4b --- /dev/null +++ b/.idea/modules.xml.orig @@ -0,0 +1,14 @@ + + + + +<<<<<<< HEAD + + +======= + + +>>>>>>> lindenberg + + + \ No newline at end of file diff --git a/app/build.gradle.orig b/app/build.gradle.orig new file mode 100644 index 0000000..8055b19 --- /dev/null +++ b/app/build.gradle.orig @@ -0,0 +1,38 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + buildToolsVersion '29.0.2' + + defaultConfig { + applicationId "de.fhws.indoor.sensorreadout" + minSdkVersion 21 +<<<<<<< HEAD + targetSdkVersion 23 +======= + targetSdkVersion 29 +>>>>>>> lindenberg + versionCode 1 + versionName "1.0" + multiDexEnabled true + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation 'com.android.support:design:28.0.0' + implementation fileTree(include: ['*.jar'], dir: 'libs') + testImplementation 'junit:junit:4.12' + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.google.android.gms:play-services:12.0.1' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'org.apmem.tools:layouts:1.10@aar' + //compile 'com.google.android.support:wearable:1.3.0' + //compile 'com.google.android.gms:play-services-wearable:8.4.0' + //provided 'com.google.android.wearable:wearable:1.0.0' +} 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 2213a70..5a385e6 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java @@ -39,7 +39,8 @@ 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.UnorderedLogger; +import de.fhws.indoor.sensorreadout.sensors.OrderedLogger; +//import de.fhws.indoor.sensorreadout.sensors.UnorderedLogger; import de.fhws.indoor.sensorreadout.sensors.WiFi; import de.fhws.indoor.sensorreadout.sensors.WiFiRTT; import de.fhws.indoor.sensorreadout.sensors.iBeacon; @@ -57,7 +58,7 @@ public class MainActivity extends Activity { private final ArrayList sensors = new ArrayList(); //private final Logger logger = new Logger(this); //private final LoggerRAM logger = new LoggerRAM(this); - private final UnorderedLogger logger = new UnorderedLogger(this); + private final OrderedLogger logger = new OrderedLogger(this); private Button btnStart; private Button btnStop; private Button btnGround; @@ -452,25 +453,25 @@ public class MainActivity extends Activity { @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } }); } -// if(activeSensors.contains("WIFI")) { -// // log wifi using sensor number 8 -// final WiFi wifi = new WiFi(this); -// sensors.add(wifi); -// wifi.setListener(new mySensor.SensorListener() { -// @Override public void onData(final long timestamp, final String csv) { add(SensorType.WIFI, csv, timestamp); } -// @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } -// }); -// } if(activeSensors.contains("WIFI")) { - // log wifi RTT using sensor number 17 - final WiFiRTT wifirtt = new WiFiRTT(this); - sensors.add(wifirtt); - wifirtt.setListener(new mySensor.SensorListener() { - @Override public void onData(final long timestamp, final String csv) { add(SensorType.WIFIRTT, csv, timestamp); } - @Override public void onData(final SensorType id, final long timestamp, final String csv) { add(SensorType.WIFIRTT, csv, timestamp); } + // log wifi using sensor number 8 + final WiFi wifi = new WiFi(this); + sensors.add(wifi); + wifi.setListener(new mySensor.SensorListener() { + @Override public void onData(final long timestamp, final String csv) { add(SensorType.WIFI, csv, timestamp); } + @Override public void onData(final SensorType id, final long timestamp, final String csv) {return; } }); - } +// if(activeSensors.contains("WIFI")) { +// // log wifi RTT using sensor number 17 +// final WiFiRTT wifirtt = new WiFiRTT(this); +// sensors.add(wifirtt); +// wifirtt.setListener(new mySensor.SensorListener() { +// @Override public void onData(final long timestamp, final String csv) { add(SensorType.WIFIRTT, csv, timestamp); } +// @Override public void onData(final SensorType id, final long timestamp, final String csv) { add(SensorType.WIFIRTT, csv, timestamp); } +// }); +// +// } if(activeSensors.contains("BLUETOOTH")) { // bluetooth permission if(ActivityCompat.shouldShowRequestPermissionRationale(this, diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java new file mode 100644 index 0000000..5e8c9d3 --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java @@ -0,0 +1,268 @@ +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.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * log sensor data to file + * Created by Frank on 25.03.2015. + * Re-Written by Markus on 20.06.2019. + */ +public final class OrderedLogger { + + private static final long CACHED_LINES = 10000; + + private interface ReorderBufferListener { + void onCommit(final List commitSlice); + } + + private static class ReorderBuffer { + private long cacheSize = 0; + private ArrayList inputCache; + private BlockingQueue> pendingInputCaches; + private ReorderThread reorderThread; + private ReorderBufferListener commitListener; + + //statistics + private AtomicInteger cachedEntries = new AtomicInteger(0); + private AtomicInteger writtenEntries = new AtomicInteger(0); + private long sizeTotal = 0; + + // ################# + // # ReorderBuffer # -> File + // ############## # ------------- # + // # InputCache # -> # # + // ############## ################# + // + // The InputCache is the fast-access side used by the logger, to append entries. + // If the InputCache is full, it is committed to the ReorderThread, and swapped + // for a new / empty InputCache. + // The ReorderThread sorts the ReorderBuffer, commits the upper half to the writer + // and inserts the InputCache into the ReorderBuffer + + public ReorderBuffer(long cacheSize, ReorderBufferListener commitListener) { + this.cacheSize = cacheSize; + this.commitListener = commitListener; + } + + public synchronized void start() { + inputCache = new ArrayList<>(); + inputCache.ensureCapacity((int) cacheSize); + pendingInputCaches = new ArrayBlockingQueue<>(5); + reorderThread = new ReorderThread(); + cachedEntries.set(0); + writtenEntries.set(0); + sizeTotal = 0; + reorderThread.start(); + } + + public synchronized void add(LogEntry entry) { + inputCache.add(entry); + cachedEntries.incrementAndGet(); + sizeTotal += entry.csv.length(); + if(inputCache.size() == cacheSize) { + // InputCache full, commit to ReorderThread for processing + commitInputCache(); + } + } + + public synchronized void flushAndStop() { + if(inputCache.size() > 0) { + commitInputCache(); + } + // be sure to commit an empty InputCache to signal the ReorderThread + commitInputCache(); + try { + reorderThread.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + private void commitInputCache() { + if(!pendingInputCaches.add(inputCache)) { + throw new RuntimeException("InputCaches overrun. ReorderThread can't keep up."); + } + inputCache = new ArrayList<>(); + inputCache.ensureCapacity((int) cacheSize); + } + + public int getEntriesWritten() { return writtenEntries.get(); } + public int getEntriesCached() { return cachedEntries.get(); } + public long getSizeTotal() { return sizeTotal; } + + private class ReorderThread extends Thread { + + public ReorderThread() { + setName("ReorderThread"); + setPriority(Thread.MIN_PRIORITY); + } + + @Override + public void run() { + ArrayList reorderBuffer = new ArrayList<>(); + reorderBuffer.ensureCapacity((int) cacheSize * 2); + + try { + ArrayList inputCache = null; + while((inputCache = pendingInputCaches.take()) != null) { + boolean draining = inputCache.size() == 0; + Log.d("OrderedLogger[Thread]", "Received InputCache[size:" + inputCache.size() + " -> draining:" + draining + "]"); + if(reorderBuffer.size() > (int) cacheSize || draining) { + // we are (either): + // - in running phase, reorderBuffer is filled and we need to commit + // - in draining phase, commit even if reorderBuffer is not full + Collections.sort(reorderBuffer); + List commitSlice; + if(draining) { + // we received an empty InputCache -> drain the complete ReorderBuffer into the writer. + commitSlice = reorderBuffer.subList(0, reorderBuffer.size()); + } else { + // we are mid-flight, drain cacheSize at max + commitSlice = reorderBuffer.subList(0, Math.min((int) cacheSize, reorderBuffer.size())); + } + Log.d("OrderedLogger[Thread]", "Committing[drain:" + draining + "] Chunk[size:" + commitSlice.size() + "]"); + commitListener.onCommit(commitSlice); + writtenEntries.addAndGet(commitSlice.size()); + cachedEntries.addAndGet(-commitSlice.size()); + commitSlice.clear(); + } + reorderBuffer.addAll(inputCache); + + if(reorderBuffer.size() == 0 && draining) { + Log.d("OrderedLogger[Thread]", "Draining finished"); + return; // we are done with draining the buffer + } + } + } catch(InterruptedException e) { + e.printStackTrace(); + } + } + } + } + + + + + public static final long BEGINNING_TS = -1; + + private StringBuilder stringBuilder = new StringBuilder(); + private File file; + private FileOutputStream fos; + private Context context; + + private ReorderBuffer reorderBuffer; + + /** timestamp of logging start. all entries are relative to this one */ + private long startTS = 0; + + public OrderedLogger(Context context) { + this.context = context; + } + + /** start logging (caching a couple of entries in RAM) */ + public final void start() { + + // start empty + stringBuilder.setLength(0); + reorderBuffer = new ReorderBuffer(CACHED_LINES, new ReorderBufferListener() { + @Override + public void onCommit(List commitSlice) { + for(LogEntry entry : commitSlice) { + try { + fos.write(entry.csv.getBytes()); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + }); + + // starting timestamp + startTS = SystemClock.elapsedRealtimeNanos(); + + // open the output-file immediately (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); + } + reorderBuffer.start(); + } + + /** stop logging and flush RAM-data to the flash-chip */ + public final void stop() { + reorderBuffer.flushAndStop(); + close(); + } + + public File getFile() { + return file; + } + + public int getCurrentBufferSize() {return reorderBuffer.getEntriesCached();} + public int getTotalSize() {return (int)reorderBuffer.getSizeTotal();} + + public int getNumEntries() {return reorderBuffer.getEntriesCached();} + + /** 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) { + 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.append(relTS); // relative timestamp (uses less space) + stringBuilder.append(';'); + stringBuilder.append(sensorNr.id()); + stringBuilder.append(';'); + stringBuilder.append(csv); + stringBuilder.append('\n'); + LogEntry logEntry = new LogEntry(relTS, stringBuilder.toString()); + reorderBuffer.add(logEntry); + stringBuilder.setLength(0); + } + } + + private final void close() { + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while wriyting log-file", e); + } + } + + public final long getStartTS() { + return startTS; + } + + + 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/build.gradle b/build.gradle index 5d652f1..8791699 100644 --- a/build.gradle +++ b/build.gradle @@ -11,7 +11,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:3.4.2' + classpath 'com.android.tools.build:gradle:3.5.0' // 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 de55c05..18c3465 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Sun Aug 18 15:19:02 CEST 2019 +#Tue Apr 07 13:33:43 CEST 2020 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip