diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index bdcd3a6..35a854e 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/gradle.xml b/.idea/gradle.xml index ee635a3..5cd135a 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -1,11 +1,10 @@ + diff --git a/.idea/modules.xml b/.idea/modules.xml index 9a8c334..14757c1 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,7 +2,9 @@ + + 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 d863320..f3a2941 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MainActivity.java @@ -1,7 +1,6 @@ package de.fhws.indoor.sensorreadout; import android.Manifest; -import android.app.Activity; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -11,13 +10,16 @@ import android.media.MediaPlayer; import android.os.Build; import android.os.Bundle; import android.os.SystemClock; -import android.preference.PreferenceManager; + +import androidx.appcompat.app.AppCompatActivity; +import androidx.preference.PreferenceManager; import androidx.core.app.ActivityCompat; //import android.support.wearable.activity.WearableActivity; import android.util.Log; import android.view.View; import android.widget.ArrayAdapter; import android.widget.Button; +import android.widget.ProgressBar; import android.widget.Spinner; import android.widget.TableLayout; import android.widget.TableRow; @@ -32,14 +34,13 @@ import java.util.HashSet; import java.util.List; import java.util.Set; +import de.fhws.indoor.sensorreadout.loggers.Logger; +import de.fhws.indoor.sensorreadout.loggers.OrderedLogger; 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.PedestrianActivity; import de.fhws.indoor.sensorreadout.sensors.PedestrianActivityButton; import de.fhws.indoor.sensorreadout.sensors.PhoneSensors; -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; @@ -47,7 +48,7 @@ import de.fhws.indoor.sensorreadout.sensors.mySensor; import de.fhws.indoor.sensorreadout.sensors.SensorType; -public class MainActivity extends Activity { +public class MainActivity extends AppCompatActivity { MediaPlayer mpStart; MediaPlayer mpStop; @@ -57,11 +58,13 @@ 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 OrderedLogger logger = new OrderedLogger(this); + private final Logger logger = new OrderedLogger(this); private Button btnStart; + private Button btnMetadata; private Button btnStop; private Button btnGround; private Button btnSettings; + private ProgressBar prgCacheFillStatus; private TableLayout activityButtonContainer; private HashMap activityButtons = new HashMap<>(); private PedestrianActivity currentPedestrianActivity = PedestrianActivity.STANDING; @@ -72,6 +75,10 @@ public class MainActivity extends Activity { final private int MY_PERMISSIONS_REQUEST_READ_BT = 123; final private int MY_PERMISSIONS_REQUEST_READ_HEART = 321; + // file metadata + private String metaPerson = ""; + private String metaComment = ""; + // static context access private static Context context; @@ -115,11 +122,14 @@ public class MainActivity extends Activity { //get Buttons btnStart = (Button) findViewById(R.id.btnStart); + btnMetadata = (Button) findViewById(R.id.btnMetadata); btnStop = (Button) findViewById(R.id.btnStop); btnGround = (Button) findViewById(R.id.btnGround); btnSettings = (Button) findViewById(R.id.btnSettings); activityButtonContainer = (TableLayout) findViewById(R.id.pedestrianActivityButtonContainer); + prgCacheFillStatus = (ProgressBar) findViewById(R.id.prgCacheFillStatus); + // log GroundTruth ButtonClicks using sensor number 99 final GroundTruth grndTruth = new GroundTruth(this); sensors.add(grndTruth); @@ -157,6 +167,26 @@ public class MainActivity extends Activity { } }); + btnMetadata.setOnClickListener(new View.OnClickListener() { + @Override public void onClick(View v) { + if(!isInitialized){ + MetadataFragment metadataDialog = new MetadataFragment(metaPerson, metaComment, new MetadataFragment.ResultListener() { + @Override public void onCommit(String person, String comment) { + metaPerson = person; + metaComment = comment; + Log.d("MetadataDialog", "Person: " + person + " Comment: " + comment); + } + + @Override public void onClose() {} + }); + metadataDialog.show(getSupportFragmentManager(), "metadata"); + } + else{ + mpFailure.start(); + } + } + }); + btnStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(isInitialized){ @@ -227,16 +257,16 @@ public class MainActivity extends Activity { private void start() { loadCounterAny = 0; - logger.start(); + logger.start(new Logger.FileMetadata(metaPerson, metaComment)); final TextView txt = (TextView) findViewById(R.id.txtFile); - String path = logger.getFile().getAbsolutePath(); - txt.setText(path.substring(path.length()-17, path.length())); + txt.setText(logger.getName()); for (final mySensor s : sensors) {s.onResume(this);} } private void stop() { for (final mySensor s : sensors) {s.onPause(this);} logger.stop(); + updateStatistics(SystemClock.elapsedRealtimeNanos()); ((TextView) findViewById(R.id.txtWifi)).setText("-"); ((TextView) findViewById(R.id.txtBeacon)).setText("-"); ((TextView) findViewById(R.id.txtGPS)).setText("-"); @@ -277,19 +307,24 @@ public class MainActivity extends Activity { // 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"); - } - }); + updateStatistics(timestamp); } } + private void updateStatistics(final long timestamp) { + 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.getSizeTotal() / 1024.0f / elapsedMinutes); + txt.setText((logger.getSizeTotal() / 1024) + "k, " + logger.getEventCnt() + ", " + kBPerMin + "kB/m"); + prgCacheFillStatus.setProgress((int)(logger.getCacheLevel() * 1000)); + } + }); + } + /** pause activity */ protected void onPause() { //stop(); diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/MetadataFragment.java b/app/src/main/java/de/fhws/indoor/sensorreadout/MetadataFragment.java new file mode 100644 index 0000000..4b97d5a --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MetadataFragment.java @@ -0,0 +1,73 @@ +package de.fhws.indoor.sensorreadout; + +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.widget.EditText; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.appcompat.app.AlertDialog; +import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; +import androidx.fragment.app.FragmentTransaction; + +public class MetadataFragment extends DialogFragment { + + public interface ResultListener { + + void onCommit(String person, String comment); + void onClose(); + + } + + private String person; + private String comment; + private ResultListener resultListener; + + public MetadataFragment(@NonNull String person, @NonNull String comment, @NonNull ResultListener resultListener) { + this.person = person; + this.comment = comment; + this.resultListener = resultListener; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + // Get the layout inflater + final LayoutInflater inflater = requireActivity().getLayoutInflater(); + final View view = inflater.inflate(R.layout.dialog_metadata, null); + + final EditText txtPerson = view.findViewById(R.id.txtPerson); + final EditText txtComment = view.findViewById(R.id.txtComment); + + // Inflate and set the layout for the dialog + // Pass null as the parent view because its going in the dialog layout + builder.setView(view) + // Add action buttons + .setPositiveButton(R.string.save, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + String person = txtPerson.getText().toString(); + String comment = txtComment.getText().toString(); + resultListener.onCommit(person, comment); + resultListener.onClose(); + } + }) + .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() { + public void onClick(DialogInterface dialog, int id) { + MetadataFragment.this.getDialog().cancel(); + resultListener.onClose(); + } + }); + Dialog dialog = builder.create(); + + // restore values + txtPerson.setText(person); + txtComment.setText(comment); + + return dialog; + } +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/MyException.java b/app/src/main/java/de/fhws/indoor/sensorreadout/MyException.java similarity index 75% rename from app/src/main/java/de/fhws/indoor/sensorreadout/sensors/MyException.java rename to app/src/main/java/de/fhws/indoor/sensorreadout/MyException.java index 9f4f9c8..27bc512 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/MyException.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/MyException.java @@ -1,4 +1,4 @@ -package de.fhws.indoor.sensorreadout.sensors; +package de.fhws.indoor.sensorreadout; import android.widget.Toast; @@ -11,12 +11,12 @@ import de.fhws.indoor.sensorreadout.R; public class MyException extends RuntimeException { - MyException(final String err, final Throwable t) { + public MyException(final String err, final Throwable t) { super(err, t); Toast.makeText(MainActivity.getAppContext(), err, Toast.LENGTH_LONG); } - MyException(final String err) { + public MyException(final String err) { super(err); Toast.makeText(MainActivity.getAppContext(), err, Toast.LENGTH_LONG); } diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java index 95b068f..a9243f2 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/SettingsFragment.java @@ -1,7 +1,6 @@ package de.fhws.indoor.sensorreadout; import android.os.Bundle; -import androidx.annotation.Nullable; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.SwitchPreferenceCompat; diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/DataFolder.java b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/DataFolder.java similarity index 94% rename from app/src/main/java/de/fhws/indoor/sensorreadout/sensors/DataFolder.java rename to app/src/main/java/de/fhws/indoor/sensorreadout/loggers/DataFolder.java index 16e7929..fa0d00d 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/DataFolder.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/DataFolder.java @@ -1,12 +1,13 @@ -package de.fhws.indoor.sensorreadout.sensors; +package de.fhws.indoor.sensorreadout.loggers; import android.content.Context; -import android.os.Build; import android.os.Environment; import android.util.Log; import java.io.File; +import de.fhws.indoor.sensorreadout.MyException; + /** * Created by toni on 02/06/16. */ diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/Logger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/Logger.java new file mode 100644 index 0000000..602522b --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/Logger.java @@ -0,0 +1,113 @@ +package de.fhws.indoor.sensorreadout.loggers; + +import android.content.Context; +import android.os.SystemClock; + +import androidx.annotation.NonNull; + +import java.util.Date; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; + +import de.fhws.indoor.sensorreadout.sensors.SensorType; + +public abstract class Logger { + + public static final long BEGINNING_TS = -1; + + // work data + private StringBuilder stringBuilder = new StringBuilder(); + protected Context context; + /** timestamp of logging start. all entries are relative to this one */ + protected long startTs = 0; + + //statistics + private AtomicLong statEntryCnt = new AtomicLong(0); + private AtomicLong statSizeTotal = new AtomicLong(0); + + public Logger(Context context) { + this.context = context; + } + + + public final void start(FileMetadata metadata) { + statEntryCnt.set(0); + statSizeTotal.set(0); + stringBuilder.setLength(0); + // starting timestamp + startTs = SystemClock.elapsedRealtimeNanos(); + onStart(); + + // commit metadata + addCSV(SensorType.FILE_METADATA, BEGINNING_TS, metadata.toCsv()); + } + public abstract void onStart(); + + public final void stop() { + onStop(); + } + public abstract void onStop(); + + protected abstract void log(LogEntry logEntry); + + public final long getStartTS() { + return startTs; + } + public final long getSizeTotal() { return statSizeTotal.get(); } + public final long getEventCnt() { return statEntryCnt.get(); } + public abstract long getEntriesCached(); + public abstract float getCacheLevel(); + public abstract String getName(); + + /** 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 == Logger.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'); + log(new LogEntry(relTS, stringBuilder.toString())); + statEntryCnt.incrementAndGet(); + statSizeTotal.addAndGet(stringBuilder.length()); + stringBuilder.setLength(0); + } + } + + public 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); + } + } + + public static class FileMetadata { + private String person; + private String comment; + private Date date; + + public FileMetadata(String person, String comment) { + this(person, comment, new Date()); + } + public FileMetadata(String person, String comment, Date date) { + this.person = person; + this.comment = comment; + this.date = date; + } + + protected String toCsv() { + return date.toString() + ";" + person + ";" + comment; + } + } + +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/LoggerRAM.java b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/LoggerRAM.java new file mode 100644 index 0000000..6f498c6 --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/LoggerRAM.java @@ -0,0 +1,95 @@ +package de.fhws.indoor.sensorreadout.loggers; + +import android.content.Context; +import android.os.SystemClock; +import androidx.annotation.NonNull; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.ArrayList; +import java.util.Collections; + +import de.fhws.indoor.sensorreadout.MyException; +import de.fhws.indoor.sensorreadout.sensors.SensorType; + +/** + * log sensor data to RAM + * only flush to file when finished + * + * WARNING: overflows RAM on some smartphones, with large recordings + */ +public final class LoggerRAM extends Logger { + + private File file; + private FileOutputStream fos; + + private ArrayList buffer = new ArrayList<>(); + + public LoggerRAM(Context context) { + super(context); + } + + @Override + public void onStart() { + buffer.clear(); + // 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); + } + } + + @Override + public void onStop() { + 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(); + } + + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while writing log-file", e); + } + } + + @Override + protected void log(LogEntry logEntry) { + synchronized (buffer) { + buffer.add(logEntry); + } + } + + @Override + public long getEntriesCached() { + return 0; + } + + @Override + public float getCacheLevel() { + return 0; + } + + @Override + public String getName() { + return null; + } +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/OrderedLogger.java similarity index 75% rename from app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java rename to app/src/main/java/de/fhws/indoor/sensorreadout/loggers/OrderedLogger.java index 6e86315..0a007ea 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/OrderedLogger.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/OrderedLogger.java @@ -1,8 +1,6 @@ -package de.fhws.indoor.sensorreadout.sensors; +package de.fhws.indoor.sensorreadout.loggers; import android.content.Context; -import android.os.SystemClock; -import androidx.annotation.NonNull; import android.util.Log; import java.io.File; @@ -15,15 +13,91 @@ import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicInteger; +import de.fhws.indoor.sensorreadout.MyException; + /** - * log sensor data to file - * Created by Frank on 25.03.2015. - * Re-Written by Markus on 20.06.2019. + * live-reorder logged sensor data, and write to file + * Created by Markus on 07.04.2020. */ -public final class OrderedLogger { +public final class OrderedLogger extends Logger { private static final long CACHED_LINES = 10000; + // members + private File file; + private FileOutputStream fos; + private ReorderBuffer reorderBuffer; + + public OrderedLogger(Context context) { + super(context); + } + + @Override + public final void onStart() { + 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(); + } + } + } + }); + + // 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(); + } + + @Override + public void onStop() { + reorderBuffer.flushAndStop(); + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while wriyting log-file", e); + } + } + + @Override + protected void log(LogEntry logEntry) { + synchronized (reorderBuffer) { + reorderBuffer.add(logEntry); + } + } + + @Override + public long getEntriesCached() { + return reorderBuffer.getEntriesCached(); + } + + @Override + public float getCacheLevel() { + // 5 InputCache slots + ReorderBuffer + return (float)reorderBuffer.getEntriesCached() / (float)(6 * CACHED_LINES); + } + + @Override + public String getName() { + if(file != null) { + return file.getName(); + } + return "OrderedLogger"; + } + + private interface ReorderBufferListener { void onCommit(final List commitSlice); } @@ -154,115 +228,4 @@ public final class OrderedLogger { } - - - 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/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/UnorderedLogger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/UnorderedLogger.java new file mode 100644 index 0000000..bffffea --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/loggers/UnorderedLogger.java @@ -0,0 +1,123 @@ +package de.fhws.indoor.sensorreadout.loggers; + +import android.content.Context; +import android.util.Log; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; + +import de.fhws.indoor.sensorreadout.MyException; + +/** + * log sensor data to file + * Created by Frank on 25.03.2015. + * Re-Written by Markus on 20.06.2019. + * Re-Written by Markus on 07.04.2020. + */ +public final class UnorderedLogger extends Logger { + + private static final int LINE_BUFFER_SIZE = 5000; + + private File file; + private FileOutputStream fos; + + private volatile boolean addingStopped = false; // Just to be sure + private ArrayBlockingQueue lineBuffer = new ArrayBlockingQueue<>(LINE_BUFFER_SIZE); + private WriteBackWorker writeBackWorker; + + public UnorderedLogger(Context context) { + super(context); + } + + @Override + public void onStart() { + writeBackWorker = new WriteBackWorker(); + + // 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); + } + writeBackWorker.start(); + } + + @Override + public void onStop() { + addingStopped = true; + try { + writeBackWorker.join(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + try { + fos.close(); + } catch (final Exception e) { + throw new MyException("error while writing log-file", e); + } + } + + @Override + protected void log(LogEntry logEntry) { + lineBuffer.add(logEntry); + } + + @Override + public long getEntriesCached() { + return lineBuffer.size(); + } + + @Override + public float getCacheLevel() { + return 1.0f - (float)lineBuffer.remainingCapacity() / (float)LINE_BUFFER_SIZE; + } + + @Override + public String getName() { + if(file != null) { + return file.getName(); + } + return "OrderedLogger"; + } + + + + + private class WriteBackWorker extends Thread { + + public WriteBackWorker() { + setName("WriteBackWorker"); + setPriority(Thread.MIN_PRIORITY); + } + + @Override + public void run() { + try { + while (true) { + LogEntry entry = lineBuffer.poll(); + if (entry == null) { + if (addingStopped) { // Queue empty, recording stopped. exit + return; + } else { // Currently no line in queue, wait 10 ms + Thread.sleep(10); + } + } else { // print log line + fos.write(entry.csv.getBytes()); + } + } + } catch(InterruptedException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + +} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java index 2ef3e03..653a060 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Gps.java @@ -12,6 +12,8 @@ import android.os.Build; import android.os.Bundle; import androidx.core.content.ContextCompat; +import de.fhws.indoor.sensorreadout.MyException; + /** * Created by student on 20.03.17. */ 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 deleted file mode 100644 index 815800b..0000000 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/Logger.java +++ /dev/null @@ -1,212 +0,0 @@ -package de.fhws.indoor.sensorreadout.sensors; - -import android.content.Context; -import android.os.SystemClock; -import androidx.annotation.NonNull; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.PriorityQueue; -import java.util.concurrent.Semaphore; - -/** - * log sensor data to file - * Created by Frank on 25.03.2015. - * Re-Written by Markus on 20.06.2019. - */ -public final class Logger { - - public static final long BEGINNING_TS = -1; - - private static final int CACHED_ENTRIES = 1000; - private static final int FLUSH_BATCH_SIZE = 100; - - private StringBuilder stringBuilder = new StringBuilder(); - private File file; - private FileOutputStream fos; - private Context context; - - private int entries = 0; - private int sizeTotal = 0; - private int currentSize = 0; - - private volatile boolean addingStopped = false; // Just to be sure - private PriorityQueue reorderBuffer = new PriorityQueue<>(2 * CACHED_ENTRIES + FLUSH_BATCH_SIZE); - private Semaphore flushSemaphore = new Semaphore(0); - private WriteBackWorker writeBackWorker; - - /** timestamp of logging start. all entries are relative to this one */ - private long startTS = 0; - - public Logger(Context context) { - this.context = context; - } - - /** start logging (into RAM) */ - public final void start() { - - // start empty - stringBuilder.setLength(0); - entries = 0; - sizeTotal = 0; - addingStopped = false; - flushSemaphore.drainPermits(); - writeBackWorker = new WriteBackWorker(); - - // 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); - } - writeBackWorker.start(); - } - - /** stop logging and flush RAM-data to the flash-chip */ - public final void stop() { - debug(true); - synchronized (reorderBuffer) { - addingStopped = true; - // Unblock WriteBackThread for all remaining log-lines (+1) - // some elements in reorderBuffer could already have been released for flushing -> this might release more than necessary. - flushSemaphore.release(reorderBuffer.size() + 1); - } - // wait for flushing to succeed - try { - writeBackWorker.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - debug(true); - 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) { - final long relTS = (timestamp == BEGINNING_TS) ? 0 : (timestamp - startTS); - if(relTS >= 0) { // drop pre startTS logs (at the beginning, sensors sometimes deliver old values) - synchronized (reorderBuffer) { - if(addingStopped) { - // addCSV was called after calling stop(); - return; - } - - 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(); - stringBuilder.setLength(0); - - // commit to reorder-buffer and start flush (if necessary) - reorderBuffer.add(logEntry); - if(flushSemaphore.availablePermits() == 0 && reorderBuffer.size() > (CACHED_ENTRIES + FLUSH_BATCH_SIZE)) { - // Unblock WriteBackThread and allow it to flush FLUSH_BATCH_SIZE csv-lines. - flushSemaphore.release(reorderBuffer.size() - CACHED_ENTRIES); - } - } - } - debug(false); - } - - 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: " + reorderBuffer.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); - } - } - - private class WriteBackWorker extends Thread { - - public WriteBackWorker() { - setName("WriteBackWorker"); - setPriority(Thread.MIN_PRIORITY); - } - - @Override - public void run() { - try { - boolean stop = false; - while(!stop) { - flushSemaphore.acquireUninterruptibly(); - - LogEntry[] entriesToFlush = null; - synchronized (reorderBuffer) { - int flushBatchSize = 1 + flushSemaphore.drainPermits(); // might contain extra-permit for stop-unblocking - if(flushBatchSize > reorderBuffer.size()) { // We were unblocked more than there are available lines to fush -> request to flush all & stop - stop = true; - flushBatchSize = reorderBuffer.size(); - } - entriesToFlush = new LogEntry[flushBatchSize]; - - for(int i = 0; i < flushBatchSize; ++i) { - entriesToFlush[i] = reorderBuffer.poll(); - currentSize -= entriesToFlush[i].csv.length(); - } - } - - for(int i = 0; i < entriesToFlush.length; ++i) { - fos.write(entriesToFlush[i].csv.getBytes()); - } - } - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - -} 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 deleted file mode 100644 index f40dd8d..0000000 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/LoggerRAM.java +++ /dev/null @@ -1,171 +0,0 @@ -package de.fhws.indoor.sensorreadout.sensors; - -import android.content.Context; -import android.os.SystemClock; -import androidx.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 Long.compare(timestamp, another.timestamp); - } - } - -} diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java index a3bc8bd..b06f9ac 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/PhoneSensors.java @@ -9,12 +9,12 @@ import android.hardware.SensorManager; import android.os.Build; import android.util.Log; -import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; -import java.io.FileWriter; import java.io.IOException; +import de.fhws.indoor.sensorreadout.loggers.DataFolder; + /** * all available sensors * and what to do within one class diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java index 4a7830b..7c21717 100644 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/SensorType.java @@ -28,6 +28,7 @@ public enum SensorType { PEDESTRIAN_ACTIVITY(50), GROUND_TRUTH(99), GROUND_TRUTH_PATH(-1), + FILE_METADATA(-2) ; diff --git a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/UnorderedLogger.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/UnorderedLogger.java deleted file mode 100644 index 9c38ea7..0000000 --- a/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/UnorderedLogger.java +++ /dev/null @@ -1,187 +0,0 @@ -package de.fhws.indoor.sensorreadout.sensors; - -import android.content.Context; -import android.os.SystemClock; -import androidx.annotation.NonNull; -import android.util.Log; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.util.concurrent.ArrayBlockingQueue; - -/** - * log sensor data to file - * Created by Frank on 25.03.2015. - * Re-Written by Markus on 20.06.2019. - */ -public final class UnorderedLogger { - - public static final long BEGINNING_TS = -1; - - private StringBuilder stringBuilder = new StringBuilder(); - private File file; - private FileOutputStream fos; - private Context context; - - private int entries = 0; - private int sizeTotal = 0; - private int currentSize = 0; - - private volatile boolean addingStopped = false; // Just to be sure - private ArrayBlockingQueue lineBuffer = new ArrayBlockingQueue<>(5000); - private WriteBackWorker writeBackWorker; - - /** timestamp of logging start. all entries are relative to this one */ - private long startTS = 0; - - public UnorderedLogger(Context context) { - this.context = context; - } - - /** start logging (caching a couple of entries in RAM) */ - public final void start() { - - // start empty - stringBuilder.setLength(0); - entries = 0; - sizeTotal = 0; - addingStopped = false; - writeBackWorker = new WriteBackWorker(); - - // 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); - } - writeBackWorker.start(); - } - - /** stop logging and flush RAM-data to the flash-chip */ - public final void stop() { - debug(true); - addingStopped = true; - // wait for flushing to succeed - try { - writeBackWorker.join(); - } catch (InterruptedException e) { - e.printStackTrace(); - } - debug(true); - 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) { - final long relTS = (timestamp == BEGINNING_TS) ? 0 : (timestamp - startTS); - if(relTS >= 0) { // drop pre startTS logs (at the beginning, sensors sometimes deliver old values) - if(addingStopped) { - // addCSV was called after calling stop(); - return; - } - - 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(); - stringBuilder.setLength(0); - - - // Commit to line/flush buffer - lineBuffer.add(logEntry); - } - debug(false); - } - - 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: " + lineBuffer.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); - } - } - - private class WriteBackWorker extends Thread { - - public WriteBackWorker() { - setName("WriteBackWorker"); - setPriority(Thread.MIN_PRIORITY); - } - - @Override - public void run() { - try { - while (true) { - LogEntry entry = lineBuffer.poll(); - if (entry == null) { - if (addingStopped) { // Queue empty, recording stopped. exit - return; - } else { // Currently no line in queue, wait 10 ms - Thread.sleep(10); - } - } else { // print log line - fos.write(entry.csv.getBytes()); - } - } - } catch(InterruptedException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - } - - -} 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 e0d57d1..bb845d5 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 @@ -7,12 +7,13 @@ import android.content.Intent; import android.content.IntentFilter; import android.net.wifi.ScanResult; import android.net.wifi.WifiManager; -import android.os.Debug; import android.util.Log; import java.lang.reflect.Method; import java.util.List; +import de.fhws.indoor.sensorreadout.MyException; + /** * Created by Frank on 25.03.2015. diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index d1a9090..a362c1d 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -30,14 +30,30 @@ android:background="@drawable/btnstopcolor" android:text="stop" /> -