diff --git a/.gitignore b/.gitignore index c6cbe56..ee0edd3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ .DS_Store /build /captures +/.idea/caches/build_file_checksums.ser diff --git a/.idea/caches/build_file_checksums.ser b/.idea/caches/build_file_checksums.ser index c0a1d75..df31f89 100644 Binary files a/.idea/caches/build_file_checksums.ser and b/.idea/caches/build_file_checksums.ser differ diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index cd6d7b7..55d94cb 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -6,4 +6,4 @@ - \ No newline at end of file + diff --git a/app/build.gradle b/app/build.gradle index cab69e3..ed6e91f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -21,11 +21,11 @@ android { } dependencies { - implementation 'com.android.support:design:23.4.0' - compile fileTree(include: ['*.jar'], dir: 'libs') - testCompile 'junit:junit:4.12' - implementation 'com.android.support:appcompat-v7:23.4.0' - implementation 'com.google.android.gms:play-services:10.2.0' + 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' diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index de7f3dc..553e304 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,10 +10,9 @@ - + - sensors = new ArrayList(); //private final Logger logger = new Logger(this); - private final LoggerRAM logger = new LoggerRAM(this); + //private final LoggerRAM logger = new LoggerRAM(this); + private final UnorderedLogger logger = new UnorderedLogger(this); private Button btnStart; private Button btnStop; private Button btnGround; @@ -261,7 +263,7 @@ public class MainActivity extends Activity { if (id == SensorType.WIFIRTT) { final TextView txt = (TextView) findViewById(R.id.txtWifi); - txt.setText(((++loadCounterWifi % 2) == 0) ? "wi" : "WI"); + txt.setText(((++loadCounterWifi % 7) == 0) ? "wi" : "WI"); } else if (id == SensorType.IBEACON) { final TextView txt = (TextView) findViewById(R.id.txtBeacon); txt.setText(((++loadCounterBeacon % 2) == 0) ? "ib" : "IB"); @@ -425,13 +427,13 @@ public class MainActivity extends Activity { if(activeSensors.contains("PHONE")) { // heartbeat permission - if(ActivityCompat.shouldShowRequestPermissionRationale(this, - Manifest.permission.BODY_SENSORS)) { - } else { - ActivityCompat.requestPermissions(this, - new String[]{Manifest.permission.BODY_SENSORS}, - MY_PERMISSIONS_REQUEST_READ_HEART); - } +// if(ActivityCompat.shouldShowRequestPermissionRationale(this, +// Manifest.permission.BODY_SENSORS)) { +// } else { +// ActivityCompat.requestPermissions(this, +// new String[]{Manifest.permission.BODY_SENSORS}, +// MY_PERMISSIONS_REQUEST_READ_HEART); +// } //all Phone-Sensors (Accel, Gyro, Magnet, ...) final PhoneSensors phoneSensors = new PhoneSensors(this); @@ -479,6 +481,8 @@ public class MainActivity extends Activity { MY_PERMISSIONS_REQUEST_READ_BT); } + //TODO: add something that asks the user to also enable GPS! + // log iBeacons using sensor number 9 final mySensor beacon; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { 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 ebd04e9..a3bc8bd 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 @@ -24,7 +24,7 @@ import java.io.IOException; */ public class PhoneSensors extends mySensor implements SensorEventListener{ - private static final int SENSOR_TYPE_HEARTRATE = 65562; + //private static final int SENSOR_TYPE_HEARTRATE = 65562; private SensorManager sensorManager; private Sensor acc; @@ -34,7 +34,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ private Sensor magnet; private Sensor press; private Sensor ori; - private Sensor heart; + //private Sensor heart; private Sensor humidity; private Sensor rotationVector; private Sensor light; @@ -61,7 +61,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ magnet = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD); press = sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE); ori = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION); - heart = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE); + //heart = sensorManager.getDefaultSensor(Sensor.TYPE_HEART_RATE); humidity = sensorManager.getDefaultSensor(Sensor.TYPE_RELATIVE_HUMIDITY); rotationVector = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR); light = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); @@ -103,7 +103,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ dumpSensor(sb, SensorType.ORIENTATION_OLD, ori); dumpSensor(sb, SensorType.LIGHT, light); dumpSensor(sb, SensorType.AMBIENT_TEMPERATURE, temperature); - dumpSensor(sb, SensorType.HEART_RATE, heart); + //dumpSensor(sb, SensorType.HEART_RATE, heart); dumpSensor(sb, SensorType.GAME_ROTATION_VECTOR, gameRotationVector); // write @@ -156,16 +156,16 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ } - if(event.sensor.getType() == Sensor.TYPE_HEART_RATE) { - - // inform listeners - if (listener != null){ - listener.onData(SensorType.HEART_RATE, event.timestamp, - Float.toString(event.values[0]) - ); - } - - } +// if(event.sensor.getType() == Sensor.TYPE_HEART_RATE) { +// +// // inform listeners +// if (listener != null){ +// listener.onData(SensorType.HEART_RATE, event.timestamp, +// Float.toString(event.values[0]) +// ); +// } +// +// } else if(event.sensor.getType() == Sensor.TYPE_LIGHT) { @@ -410,7 +410,7 @@ public class PhoneSensors extends mySensor implements SensorEventListener{ registerIfPresent(magnet, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(press, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(ori, SensorManager.SENSOR_DELAY_FASTEST); - registerIfPresent(heart, SensorManager.SENSOR_DELAY_FASTEST); + //registerIfPresent(heart, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(humidity, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(rotationVector, SensorManager.SENSOR_DELAY_FASTEST); registerIfPresent(light, SensorManager.SENSOR_DELAY_FASTEST); 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 new file mode 100644 index 0000000..ee81367 --- /dev/null +++ b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/UnorderedLogger.java @@ -0,0 +1,190 @@ +package de.fhws.indoor.sensorreadout.sensors; + +import android.content.Context; +import android.os.AsyncTask; +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.PriorityQueue; +import java.util.concurrent.ArrayBlockingQueue; +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 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/iBeacon.java b/app/src/main/java/de/fhws/indoor/sensorreadout/sensors/iBeacon.java index 9b78cdf..3f3b2a7 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 @@ -5,18 +5,24 @@ import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothManager; import android.bluetooth.le.BluetoothLeScanner; import android.bluetooth.le.ScanCallback; +import android.bluetooth.le.ScanFilter; +import android.bluetooth.le.ScanSettings; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.widget.Toast; +import java.util.ArrayList; +import java.util.List; + /** * Created by Frank on 25.03.2015. */ public class iBeacon extends mySensor { - private BluetoothAdapter bt = null; - private BluetoothLeScanner scanner = null; + private BluetoothAdapter bt; + private BluetoothLeScanner scanner; + private static ScanSettings settings; private static final int REQUEST_ENABLE_BT = 1; private ScanCallback mLeScanCallback; @@ -35,7 +41,9 @@ public class iBeacon extends mySensor { bt = mgr.getAdapter(); // bluetooth supported? - if (bt == null) { + if (bt == null || !bt.isEnabled()) { + + //TODO: add something that asks the user to enable BLE. this need also be called in onResum() Toast.makeText(act, "Bluetooth not supported!", Toast.LENGTH_SHORT).show(); return; } @@ -53,9 +61,15 @@ public class iBeacon extends mySensor { } }; + settings = new ScanSettings.Builder() + .setReportDelay(0) + .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) + //.setNumOfMatches(ScanSettings.MATCH_NUM_MAX_ADVERTISEMENT) //comment this out for apk < 23 + .build(); + } - private final void enableBT(final Activity act) { + private void enableBT(final Activity act) { if (bt == null) {throw new RuntimeException("BT not supported!");} if (!bt.isEnabled()) { Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); @@ -66,7 +80,9 @@ public class iBeacon extends mySensor { @Override public void onResume(final Activity act) { if (bt != null) { enableBT(act); - scanner.startScan(mLeScanCallback); + List filters = new ArrayList(); + scanner.startScan(filters, settings, mLeScanCallback); + //scanner.startScan(mLeScanCallback); } }