Added running average for RSSI
This commit is contained in:
@@ -1,10 +1,15 @@
|
|||||||
package uk.co.alt236.bluetoothlelib.device;
|
package uk.co.alt236.bluetoothlelib.device;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecordStore;
|
import uk.co.alt236.bluetoothlelib.device.adrecord.AdRecordStore;
|
||||||
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
|
import uk.co.alt236.bluetoothlelib.util.AdRecordUtils;
|
||||||
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
import uk.co.alt236.bluetoothlelib.util.ByteUtils;
|
||||||
|
import uk.co.alt236.bluetoothlelib.util.LimitedLinkHashMap;
|
||||||
import android.bluetooth.BluetoothClass;
|
import android.bluetooth.BluetoothClass;
|
||||||
import android.bluetooth.BluetoothDevice;
|
import android.bluetooth.BluetoothDevice;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
@@ -20,16 +25,25 @@ import android.os.Parcelable;
|
|||||||
*/
|
*/
|
||||||
public class BluetoothLeDevice implements Parcelable{
|
public class BluetoothLeDevice implements Parcelable{
|
||||||
private static final String PARCEL_EXTRA_BLUETOOTH_DEVICE = "bluetooth_device";
|
private static final String PARCEL_EXTRA_BLUETOOTH_DEVICE = "bluetooth_device";
|
||||||
private static final String PARCEL_EXTRA_DEVICE_RSSI = "device_rssi";
|
private static final String PARCEL_EXTRA_CURRENT_RSSI = "current_rssi";
|
||||||
|
private static final String PARCEL_EXTRA_CURRENT_TIMESTAMP = "current_timestamp";
|
||||||
|
private static final String PARCEL_EXTRA_DEVICE_RSSI_LOG = "device_rssi_log";
|
||||||
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD = "device_scanrecord";
|
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD = "device_scanrecord";
|
||||||
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD_STORE = "device_scanrecord_store";
|
private static final String PARCEL_EXTRA_DEVICE_SCANRECORD_STORE = "device_scanrecord_store";
|
||||||
private static final String PARCEL_EXTRA_TIMESTAMP = "timestamp";
|
private static final String PARCEL_EXTRA_FIRST_RSSI = "device_first_rssi";
|
||||||
|
private static final String PARCEL_EXTRA_FIRST_TIMESTAMP = "first_timestamp";
|
||||||
|
|
||||||
|
private static final int MAX_RSSI_LOG_SIZE = 10;
|
||||||
|
private static final long LOG_INVALIDATION_THRESHOLD = 10 * 1000;
|
||||||
|
|
||||||
private final AdRecordStore mRecordStore;
|
private final AdRecordStore mRecordStore;
|
||||||
private final BluetoothDevice mDevice;
|
private final BluetoothDevice mDevice;
|
||||||
|
private final Map<Long, Integer> mRssiLog;
|
||||||
private final byte[] mScanRecord;
|
private final byte[] mScanRecord;
|
||||||
private final int mRssi;
|
private final int mFirstRssi;
|
||||||
private final long mTimestamp;
|
private final long mFirstTimestamp;
|
||||||
|
private int mCurrentRssi;
|
||||||
|
private long mCurrentTimestamp;
|
||||||
|
|
||||||
public static final Parcelable.Creator<BluetoothLeDevice> CREATOR = new Parcelable.Creator<BluetoothLeDevice>() {
|
public static final Parcelable.Creator<BluetoothLeDevice> CREATOR = new Parcelable.Creator<BluetoothLeDevice>() {
|
||||||
public BluetoothLeDevice createFromParcel(Parcel in) {
|
public BluetoothLeDevice createFromParcel(Parcel in) {
|
||||||
@@ -40,29 +54,60 @@ public class BluetoothLeDevice implements Parcelable{
|
|||||||
return new BluetoothLeDevice[size];
|
return new BluetoothLeDevice[size];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public BluetoothLeDevice(BluetoothDevice device, int rssi, byte[] scanRecord){
|
|
||||||
this(device, rssi, scanRecord, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public BluetoothLeDevice(BluetoothDevice device, int rssi, byte[] scanRecord, long timestamp){
|
public BluetoothLeDevice(BluetoothDevice device, int rssi, byte[] scanRecord, long timestamp){
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mRssi = rssi;
|
mFirstRssi = rssi;
|
||||||
mScanRecord = scanRecord;
|
mFirstTimestamp = timestamp;
|
||||||
mRecordStore = new AdRecordStore(AdRecordUtils.parseScanRecordAsSparseArray(scanRecord));
|
mRecordStore = new AdRecordStore(AdRecordUtils.parseScanRecordAsSparseArray(scanRecord));
|
||||||
mTimestamp = timestamp;
|
mScanRecord = scanRecord;
|
||||||
|
mRssiLog = Collections.synchronizedMap(
|
||||||
|
new LimitedLinkHashMap<Long, Integer>(MAX_RSSI_LOG_SIZE));
|
||||||
|
updateRssiReading(timestamp, rssi);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public double getRunningAverageRssi(){
|
||||||
|
final Collection<Integer> values = mRssiLog.values();
|
||||||
|
int sum = 0;
|
||||||
|
|
||||||
|
for(Integer value: values){
|
||||||
|
sum += value.intValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
return sum/values.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
protected BluetoothLeDevice(Parcel in) {
|
protected BluetoothLeDevice(Parcel in) {
|
||||||
final Bundle b = in.readBundle(getClass().getClassLoader());
|
final Bundle b = in.readBundle(getClass().getClassLoader());
|
||||||
|
|
||||||
|
mCurrentRssi = b.getInt(PARCEL_EXTRA_CURRENT_RSSI, 0);
|
||||||
|
mCurrentTimestamp = b.getLong(PARCEL_EXTRA_CURRENT_TIMESTAMP, 0);
|
||||||
mDevice = b.getParcelable(PARCEL_EXTRA_BLUETOOTH_DEVICE);
|
mDevice = b.getParcelable(PARCEL_EXTRA_BLUETOOTH_DEVICE);
|
||||||
|
mFirstRssi = b.getInt(PARCEL_EXTRA_FIRST_RSSI, 0);
|
||||||
|
mFirstTimestamp = b.getLong(PARCEL_EXTRA_FIRST_TIMESTAMP, 0);
|
||||||
mRecordStore = b.getParcelable(PARCEL_EXTRA_DEVICE_SCANRECORD_STORE);
|
mRecordStore = b.getParcelable(PARCEL_EXTRA_DEVICE_SCANRECORD_STORE);
|
||||||
mRssi = b.getInt(PARCEL_EXTRA_DEVICE_RSSI, 0);
|
|
||||||
mScanRecord = b.getByteArray(PARCEL_EXTRA_DEVICE_SCANRECORD);
|
mScanRecord = b.getByteArray(PARCEL_EXTRA_DEVICE_SCANRECORD);
|
||||||
mTimestamp = b.getLong(PARCEL_EXTRA_TIMESTAMP, 0);
|
|
||||||
|
mRssiLog = Collections.synchronizedMap(
|
||||||
|
(Map<Long, Integer>) b.getSerializable(PARCEL_EXTRA_DEVICE_RSSI_LOG));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void updateRssiReading(long timestamp, int rssiReading){
|
||||||
|
addToRssiLog(timestamp, rssiReading);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addToRssiLog(long timestamp, int rssiReading){
|
||||||
|
|
||||||
|
if(timestamp - mCurrentTimestamp > LOG_INVALIDATION_THRESHOLD){
|
||||||
|
mRssiLog.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentRssi = rssiReading;
|
||||||
|
mCurrentTimestamp = timestamp;
|
||||||
|
mRssiLog.put(timestamp, rssiReading);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int describeContents() {
|
public int describeContents() {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -77,11 +122,29 @@ public class BluetoothLeDevice implements Parcelable{
|
|||||||
if (getClass() != obj.getClass())
|
if (getClass() != obj.getClass())
|
||||||
return false;
|
return false;
|
||||||
BluetoothLeDevice other = (BluetoothLeDevice) obj;
|
BluetoothLeDevice other = (BluetoothLeDevice) obj;
|
||||||
|
if (mCurrentRssi != other.mCurrentRssi)
|
||||||
|
return false;
|
||||||
|
if (mCurrentTimestamp != other.mCurrentTimestamp)
|
||||||
|
return false;
|
||||||
if (mDevice == null) {
|
if (mDevice == null) {
|
||||||
if (other.mDevice != null)
|
if (other.mDevice != null)
|
||||||
return false;
|
return false;
|
||||||
} else if (!mDevice.equals(other.mDevice))
|
} else if (!mDevice.equals(other.mDevice))
|
||||||
return false;
|
return false;
|
||||||
|
if (mFirstRssi != other.mFirstRssi)
|
||||||
|
return false;
|
||||||
|
if (mFirstTimestamp != other.mFirstTimestamp)
|
||||||
|
return false;
|
||||||
|
if (mRecordStore == null) {
|
||||||
|
if (other.mRecordStore != null)
|
||||||
|
return false;
|
||||||
|
} else if (!mRecordStore.equals(other.mRecordStore))
|
||||||
|
return false;
|
||||||
|
if (mRssiLog == null) {
|
||||||
|
if (other.mRssiLog != null)
|
||||||
|
return false;
|
||||||
|
} else if (!mRssiLog.equals(other.mRssiLog))
|
||||||
|
return false;
|
||||||
if (!Arrays.equals(mScanRecord, other.mScanRecord))
|
if (!Arrays.equals(mScanRecord, other.mScanRecord))
|
||||||
return false;
|
return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -107,12 +170,20 @@ public class BluetoothLeDevice implements Parcelable{
|
|||||||
return mDevice;
|
return mDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int getFirstRssi(){
|
||||||
|
return mFirstRssi;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getFirstTimestamp(){
|
||||||
|
return mFirstTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
public String getName(){
|
public String getName(){
|
||||||
return mDevice.getName();
|
return mDevice.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getRssi() {
|
public int getRssi() {
|
||||||
return mRssi;
|
return mCurrentRssi;
|
||||||
}
|
}
|
||||||
|
|
||||||
public byte[] getScanRecord() {
|
public byte[] getScanRecord() {
|
||||||
@@ -120,21 +191,27 @@ public class BluetoothLeDevice implements Parcelable{
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long getTimestamp(){
|
public long getTimestamp(){
|
||||||
return mTimestamp;
|
return mCurrentTimestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
final int prime = 31;
|
final int prime = 31;
|
||||||
int result = 1;
|
int result = 1;
|
||||||
|
result = prime * result + mCurrentRssi;
|
||||||
|
result = prime * result + (int) (mCurrentTimestamp ^ (mCurrentTimestamp >>> 32));
|
||||||
result = prime * result + ((mDevice == null) ? 0 : mDevice.hashCode());
|
result = prime * result + ((mDevice == null) ? 0 : mDevice.hashCode());
|
||||||
|
result = prime * result + mFirstRssi;
|
||||||
|
result = prime * result + (int) (mFirstTimestamp ^ (mFirstTimestamp >>> 32));
|
||||||
|
result = prime * result + ((mRecordStore == null) ? 0 : mRecordStore.hashCode());
|
||||||
|
result = prime * result + ((mRssiLog == null) ? 0 : mRssiLog.hashCode());
|
||||||
result = prime * result + Arrays.hashCode(mScanRecord);
|
result = prime * result + Arrays.hashCode(mScanRecord);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "BluetoothLeDevice [mDevice=" + mDevice + ", mRssi=" + mRssi + ", mScanRecord=" + ByteUtils.byteArrayToHexString(mScanRecord) + ", mRecordStore=" + mRecordStore + ", getBluetoothDeviceBondState()=" + getBluetoothDeviceBondState() + ", getBluetoothDeviceClassName()=" + getBluetoothDeviceClassName() + "]";
|
return "BluetoothLeDevice [mDevice=" + mDevice + ", mRssi=" + mFirstRssi + ", mScanRecord=" + ByteUtils.byteArrayToHexString(mScanRecord) + ", mRecordStore=" + mRecordStore + ", getBluetoothDeviceBondState()=" + getBluetoothDeviceBondState() + ", getBluetoothDeviceClassName()=" + getBluetoothDeviceClassName() + "]";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -142,10 +219,16 @@ public class BluetoothLeDevice implements Parcelable{
|
|||||||
final Bundle b = new Bundle(getClass().getClassLoader());
|
final Bundle b = new Bundle(getClass().getClassLoader());
|
||||||
|
|
||||||
b.putByteArray(PARCEL_EXTRA_DEVICE_SCANRECORD, mScanRecord);
|
b.putByteArray(PARCEL_EXTRA_DEVICE_SCANRECORD, mScanRecord);
|
||||||
b.putInt(PARCEL_EXTRA_DEVICE_RSSI, mRssi);
|
|
||||||
b.putLong(PARCEL_EXTRA_TIMESTAMP, mTimestamp);
|
b.putInt(PARCEL_EXTRA_FIRST_RSSI, mFirstRssi);
|
||||||
|
b.putInt(PARCEL_EXTRA_CURRENT_RSSI, mCurrentRssi);
|
||||||
|
|
||||||
|
b.putLong(PARCEL_EXTRA_FIRST_TIMESTAMP, mFirstTimestamp);
|
||||||
|
b.putLong(PARCEL_EXTRA_CURRENT_TIMESTAMP, mCurrentTimestamp);
|
||||||
|
|
||||||
b.putParcelable(PARCEL_EXTRA_BLUETOOTH_DEVICE, mDevice);
|
b.putParcelable(PARCEL_EXTRA_BLUETOOTH_DEVICE, mDevice);
|
||||||
b.putParcelable(PARCEL_EXTRA_DEVICE_SCANRECORD_STORE, mRecordStore);
|
b.putParcelable(PARCEL_EXTRA_DEVICE_SCANRECORD_STORE, mRecordStore);
|
||||||
|
b.putSerializable(PARCEL_EXTRA_DEVICE_RSSI_LOG, (Serializable) mRssiLog);
|
||||||
|
|
||||||
parcel.writeBundle(b);
|
parcel.writeBundle(b);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import android.os.Parcel;
|
|||||||
|
|
||||||
public class IBeaconDevice extends BluetoothLeDevice{
|
public class IBeaconDevice extends BluetoothLeDevice{
|
||||||
private final IBeaconManufacturerData mIBeaconData;
|
private final IBeaconManufacturerData mIBeaconData;
|
||||||
|
|
||||||
public IBeaconDevice(BluetoothDevice device, int rssi, byte[] scanRecord) {
|
public IBeaconDevice(BluetoothDevice device, int rssi, byte[] scanRecord) {
|
||||||
super(device, rssi, scanRecord, 0);
|
super(device, rssi, scanRecord, 0);
|
||||||
mIBeaconData = new IBeaconManufacturerData(this);
|
mIBeaconData = new IBeaconManufacturerData(this);
|
||||||
@@ -22,40 +22,42 @@ public class IBeaconDevice extends BluetoothLeDevice{
|
|||||||
public IBeaconDevice(BluetoothLeDevice device){
|
public IBeaconDevice(BluetoothLeDevice device){
|
||||||
this(device.getDevice(), device.getRssi(), device.getScanRecord(), device.getTimestamp());
|
this(device.getDevice(), device.getRssi(), device.getScanRecord(), device.getTimestamp());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IBeaconDevice(Parcel in) {
|
private IBeaconDevice(Parcel in) {
|
||||||
super(in);
|
super(in);
|
||||||
mIBeaconData = new IBeaconManufacturerData(this);
|
mIBeaconData = new IBeaconManufacturerData(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getAccuracy(){
|
public double getAccuracy(){
|
||||||
return IBeaconUtils.calculateAccuracy(getCalibratedTxPower(), getRssi());
|
return IBeaconUtils.calculateAccuracy(
|
||||||
|
getCalibratedTxPower(),
|
||||||
|
getRunningAverageRssi());
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCalibratedTxPower(){
|
public int getCalibratedTxPower(){
|
||||||
return getIBeaconData().getCalibratedTxPower();
|
return getIBeaconData().getCalibratedTxPower();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getCompanyIdentifier(){
|
public int getCompanyIdentifier(){
|
||||||
return getIBeaconData().getCompanyIdentifier();
|
return getIBeaconData().getCompanyIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBeaconDistanceDescriptor getDistanceDescriptor(){
|
public IBeaconDistanceDescriptor getDistanceDescriptor(){
|
||||||
return IBeaconUtils.getDistanceDescriptor(getAccuracy());
|
return IBeaconUtils.getDistanceDescriptor(getAccuracy());
|
||||||
}
|
}
|
||||||
|
|
||||||
public IBeaconManufacturerData getIBeaconData(){
|
public IBeaconManufacturerData getIBeaconData(){
|
||||||
return mIBeaconData;
|
return mIBeaconData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMajor(){
|
public int getMajor(){
|
||||||
return getIBeaconData().getMajor();
|
return getIBeaconData().getMajor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getMinor(){
|
public int getMinor(){
|
||||||
return getIBeaconData().getMinor();
|
return getIBeaconData().getMinor();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getUUID(){
|
public String getUUID(){
|
||||||
return getIBeaconData().getUUID();
|
return getIBeaconData().getUUID();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package uk.co.alt236.bluetoothlelib.util;
|
||||||
|
|
||||||
|
import java.util.LinkedHashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class LimitedLinkHashMap<K, V> extends LinkedHashMap<K, V>{
|
||||||
|
private static final long serialVersionUID = -5375660288461724925L;
|
||||||
|
|
||||||
|
private final int mMaxSize;
|
||||||
|
public LimitedLinkHashMap(int maxSize){
|
||||||
|
super();
|
||||||
|
mMaxSize = maxSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean removeEldestEntry(Map.Entry<K, V> eldest)
|
||||||
|
{
|
||||||
|
return this.size() > mMaxSize;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user