From 82118987cbf08859105a9f7d74753d7058000151 Mon Sep 17 00:00:00 2001 From: Robert Richer Date: Tue, 26 Mar 2019 08:34:07 +0100 Subject: [PATCH 1/2] 1st version of SessionBuilder that extracts sensor data while downloading Session from NilsPod --- .../sensors/logging/SessionBuilder.java | 204 ++++++++++++++++++ .../sensors/logging/SessionDownloader.java | 6 + 2 files changed, 210 insertions(+) create mode 100644 SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionBuilder.java diff --git a/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionBuilder.java b/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionBuilder.java new file mode 100644 index 00000000..de3f04fe --- /dev/null +++ b/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionBuilder.java @@ -0,0 +1,204 @@ +/* + * Copyright (C) 2019 Machine Learning and Data Analytics Lab, Friedrich-Alexander-Universität Erlangen-Nürnberg (FAU). + *

+ * This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without + * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. If you reuse + * this code you have to keep or cite this comment. + */ + +package de.fau.sensorlib.sensors.logging; + +import android.bluetooth.BluetoothGattCharacteristic; +import android.util.Log; + +import java.nio.BufferOverflowException; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; + +import de.fau.sensorlib.enums.HardwareSensor; +import de.fau.sensorlib.sensors.AbstractSensor; +import de.fau.sensorlib.sensors.InsoleSensor; +import de.fau.sensorlib.sensors.NilsPodSensor; +import de.fau.sensorlib.sensors.enums.NilsPodRfGroup; +import de.fau.sensorlib.sensors.enums.NilsPodSyncRole; +import de.fau.sensorlib.sensors.enums.NilsPodTerminationSource; + +public class SessionBuilder { + + private static final String TAG = SessionBuilder.class.getSimpleName(); + + + private boolean mFirstPacketRead; + + private int mHeaderSize; + private int mSampleSize; + private HashMap mEnabledSensorsMap = new HashMap<>(); + + private ByteBuffer mByteBuffer; + + private AbstractSensor mSensor; + private Session mSession; + + public SessionBuilder(AbstractSensor sensor, Session session) { + mSensor = sensor; + mSession = session; + } + + public void nextPacket(byte[] values) { + if (!mFirstPacketRead) { + Log.e(TAG, Arrays.toString(values)); + mFirstPacketRead = true; + mHeaderSize = values[0]; + byte[] header = new byte[mHeaderSize]; + byte[] data = new byte[values.length - mHeaderSize]; + System.arraycopy(values, 0, header, 0, header.length); + System.arraycopy(values, mHeaderSize, data, 0, data.length); + extractHeader(header); + onNewData(data); + } else { + onNewData(values); + } + } + + // TODO TEST!!! + private synchronized void extractHeader(byte[] values) { + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(null, 0, 0); + characteristic.setValue(values); + + Log.e(TAG, "header: " + Arrays.toString(values)); + int offset = 1; + mSampleSize = values[offset++]; + + mByteBuffer = ByteBuffer.allocate(mSampleSize * 1000); + + int sensors = values[offset++]; + mEnabledSensorsMap.put(HardwareSensor.ACCELEROMETER, ((sensors & 0x01) != 0)); + mEnabledSensorsMap.put(HardwareSensor.GYROSCOPE, ((sensors & 0x01) != 0)); + mEnabledSensorsMap.put(HardwareSensor.FSR, ((sensors & 0x02) != 0)); + mEnabledSensorsMap.put(HardwareSensor.BAROMETER, ((sensors & 0x04) != 0)); + + + double samplingRate = NilsPodSensor.inferSamplingRate(values[offset] & 0x0F); + NilsPodTerminationSource terminationSource = NilsPodTerminationSource.inferTerminationSource(values[offset++] & 0xF0); + + NilsPodSyncRole syncRole = NilsPodSyncRole.values()[values[offset++]]; + int syncDistance = values[offset++] * 100; + NilsPodRfGroup rfGroup = NilsPodRfGroup.values()[values[offset++]]; + + int accRange = values[offset++]; + int gyroRange = values[offset++]; + + // metadata + int sensorPosition = values[offset++]; + int specialFunction = values[offset++]; + offset += 3; + + + int tmpTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset); + Date startTime = new Date(((long) tmpTime) * 1000); + offset += 4; + + tmpTime = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset); + // little endian + //tmpTime = (values[offset++] & 0xFF) | ((values[offset++] & 0xFF) << 8) | ((values[offset++] & 0xFF) << 16) | ((values[offset++] & 0xFF) << 24); + Date endTime = new Date(((long) tmpTime) * 1000); + offset += 4; + + //int sessionSize = ((values[offset++] & 0xFF) << 24) | ((values[offset++] & 0xFF) << 16) | ((values[offset++] & 0xFF) << 8) | (values[offset++] & 0xFF); + int sessionSize = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT32, offset); + offset += 4; + String firmwareVersion = values[offset++] + "." + values[offset++] + "." + values[offset]; + + String sb = "sample size: " + mSampleSize + "\n" + + "enabled sensors: " + mEnabledSensorsMap + "\n" + + "sampling rate: " + samplingRate + "\n" + + "termination source: " + terminationSource + "\n" + + "sync role: " + syncRole + "\n" + + "sync distance: " + syncDistance + "\n" + + "rf group: " + rfGroup + "\n" + + "acc range: " + accRange + "\n" + + "gyro range: " + gyroRange + "\n" + + "sensor position: " + sensorPosition + "\n" + + "special function: " + specialFunction + "\n" + + "start Time: " + startTime + "\n" + + "end Time: " + endTime + "\n" + + "session size: " + sessionSize + "\n" + + "firmware version: " + firmwareVersion + "\n"; + Log.e(TAG, sb); + } + + + private synchronized void onNewData(byte[] values) { + try { + mByteBuffer.put(values); + } catch (BufferOverflowException e) { + e.printStackTrace(); + } + + byte[] sample; + // flip buffer to start reading + mByteBuffer.flip(); + while (mByteBuffer.remaining() / mSampleSize > 0) { + sample = new byte[mSampleSize]; + // get one data sample + mByteBuffer.get(sample); + extractDataFrame(sample); + } + // compact buffer to shift remaining samples to beginning + mByteBuffer.compact(); + } + + + private void extractDataFrame(byte[] values) { + BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(null, 0, 0); + characteristic.setValue(values); + int offset = 0; + double[] gyro = new double[3]; + double[] accel = new double[3]; + double baro = 0; + double[] pressure = new double[3]; + int timestamp; + + if (isSensorEnabled(HardwareSensor.GYROSCOPE)) { + // extract gyroscope data + for (int j = 0; j < 3; j++) { + gyro[j] = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, offset); + offset += 2; + } + } + // extract accelerometer data + if (isSensorEnabled(HardwareSensor.ACCELEROMETER)) { + for (int j = 0; j < 3; j++) { + accel[j] = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, offset); + offset += 2; + } + } + + if (isSensorEnabled(HardwareSensor.BAROMETER)) { + baro = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_SINT16, offset); + baro = (baro + 101325.0) / 100.0; + offset += 2; + } + + if (isSensorEnabled(HardwareSensor.FSR)) { + for (int j = 0; j < 3; j++) { + pressure[j] = characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, offset); + offset++; + } + } + + timestamp = ((values[offset++] & 0xFF) << 24) | ((values[offset++] & 0xFF) << 16) | ((values[offset++] & 0xFF) << 8) | values[offset] & 0xFF; + + InsoleSensor.InsoleDataFrame df = new InsoleSensor.InsoleDataFrame(mSensor, timestamp, accel, gyro, baro, pressure); + + Log.d(TAG, df.toString()); + //mDataRecorder.writeData(df); + } + + public boolean isSensorEnabled(HardwareSensor sensor) { + return (mEnabledSensorsMap.get(sensor) != null) && mEnabledSensorsMap.get(sensor); + } + +} diff --git a/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionDownloader.java b/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionDownloader.java index 80cd62cc..c8198090 100644 --- a/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionDownloader.java +++ b/SensorLib/sls-portabiles/src/main/java/de/fau/sensorlib/sensors/logging/SessionDownloader.java @@ -24,6 +24,7 @@ public class SessionDownloader { private Session mSession; private SessionByteWriter mSessionWriter; + private SessionBuilder mSessionBuilder; // in Byte private int mProgress; @@ -60,6 +61,10 @@ public void setSessionWriter() throws SensorException { mSessionWriter = new SessionByteWriter(mSensor, mSession, mSensor.getContext()); } + public void setSessionBuilder() { + mSessionBuilder = new SessionBuilder(mSensor, mSession); + } + public void onNewData(byte[] values) { mProgress += values.length; mElapsedTime = System.currentTimeMillis() - mStartTime; @@ -74,6 +79,7 @@ public void onNewData(byte[] values) { mEstimatedRemainingTime = (long) (remainingBytes / mDownloadRate) * 1000; mSessionWriter.writeData(values); + mSessionBuilder.nextPacket(values); } public int getProgress() { From d1f1915809fc984a9d0d0a079220b1863d235186 Mon Sep 17 00:00:00 2001 From: Robert Richer Date: Wed, 27 Mar 2019 13:05:39 +0100 Subject: [PATCH 2/2] 0.4.1 LOGGING state in UI elements - added LOGGING state to StatusBar and StreamingFooter, so they can react to this global state --- SensorLib/sensorlib/build.gradle | 2 +- .../src/main/java/de/fau/sensorlib/widgets/StatusBar.java | 4 ++++ .../main/java/de/fau/sensorlib/widgets/StreamingFooter.java | 6 ++++++ SensorLib/sensorlib/src/main/res/values/colors.xml | 1 + SensorLib/sensorlib/src/main/res/values/strings.xml | 1 + 5 files changed, 13 insertions(+), 1 deletion(-) diff --git a/SensorLib/sensorlib/build.gradle b/SensorLib/sensorlib/build.gradle index 35689839..2b4214fe 100644 --- a/SensorLib/sensorlib/build.gradle +++ b/SensorLib/sensorlib/build.gradle @@ -56,7 +56,7 @@ android { def versionMajor = 0 def versionMinor = 4 - def versionPatch = 1 + def versionPatch = 2 versionCode versionMajor * 10000 + versionMinor * 100 + versionPatch versionName "${versionMajor}.${versionMinor}.${versionPatch}." + versionBuild + "_" + getGitDate() + "-" + getGitHash() diff --git a/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StatusBar.java b/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StatusBar.java index 48e1790c..956a7472 100644 --- a/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StatusBar.java +++ b/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StatusBar.java @@ -97,6 +97,10 @@ public void setState(SensorState status) { setBackgroundColor(ContextCompat.getColor(mContext, R.color.status_bar_streaming)); mStateTextView.setText(getResources().getString(R.string.status_bar_streaming, mSensorName).toUpperCase()); break; + case LOGGING: + setBackgroundColor(ContextCompat.getColor(mContext, R.color.status_bar_logging)); + mStateTextView.setText(getResources().getString(R.string.status_bar_loggging, mSensorName).toUpperCase()); + break; case SIMULATING: setBackgroundColor(ContextCompat.getColor(mContext, R.color.status_bar_simulating)); mStateTextView.setText(getResources().getString(R.string.status_bar_simulating, mSensorName).toUpperCase()); diff --git a/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StreamingFooter.java b/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StreamingFooter.java index d194f374..2b7ebc46 100644 --- a/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StreamingFooter.java +++ b/SensorLib/sensorlib/src/main/java/de/fau/sensorlib/widgets/StreamingFooter.java @@ -211,6 +211,12 @@ public void onSensorStateChange(AbstractSensor sensor, SensorState state) { mStartStopButton.setText(R.string.start); } break; + case LOGGING: + if (mFabOpen) { + mFab.performClick(); + mStartStopButton.setText(R.string.stop); + } + break; case CONNECTION_LOST: mFab.performClick(); mDisconnectButton.performClick(); diff --git a/SensorLib/sensorlib/src/main/res/values/colors.xml b/SensorLib/sensorlib/src/main/res/values/colors.xml index 9431aeb0..74401bce 100644 --- a/SensorLib/sensorlib/src/main/res/values/colors.xml +++ b/SensorLib/sensorlib/src/main/res/values/colors.xml @@ -18,6 +18,7 @@ #FF9800 #8BC34A #4CAF50 + #009688 #03A9F4 diff --git a/SensorLib/sensorlib/src/main/res/values/strings.xml b/SensorLib/sensorlib/src/main/res/values/strings.xml index c8266b29..6e026428 100644 --- a/SensorLib/sensorlib/src/main/res/values/strings.xml +++ b/SensorLib/sensorlib/src/main/res/values/strings.xml @@ -17,6 +17,7 @@ %1$s connecting %1$s connected %1$s streaming + %1$s logging %1$s simulating