package com.nexenio.bleindoorpositioning.ble.advertising; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; import java.util.UUID; import java.util.concurrent.TimeUnit; /** * Created by steppschuh on 06.12.17. */ public abstract class AdvertisingPacketUtil { public static String toHexadecimalString(byte[] bytes) { BigInteger bigInteger = new BigInteger(bytes); return "0x" + bigInteger.toString(16).toUpperCase(); } public static UUID toUuid(byte[] bytes) { ByteBuffer bb = ByteBuffer.wrap(bytes); return new UUID(bb.getLong(), bb.getLong()); } public static int[] getRssisFromAdvertisingPackets(List<? extends AdvertisingPacket> advertisingPackets) { int[] rssis = new int[advertisingPackets.size()]; for (int i = 0; i < advertisingPackets.size(); i++) { rssis[i] = advertisingPackets.get(i).getRssi(); } return rssis; } public static float calculateMean(int[] values) { int sum = 0; for (int i = 0; i < values.length; i++) { sum += values[i]; } return sum / (float) values.length; } public static float calculateVariance(int[] values) { float mean = calculateMean(values); float squaredDistanceSum = 0; for (int i = 0; i < values.length; i++) { squaredDistanceSum += Math.pow(values[i] - mean, 2); } int sampleLength = Math.max(values.length - 1, 1); return squaredDistanceSum / sampleLength; } public static float getPacketFrequency(int packetCount, long duration, TimeUnit timeUnit) { if (duration == 0) { return 0; } return packetCount / (float) (timeUnit.toSeconds(duration)); } /** * Returns an ArrayList of AdvertisingPackets that have been received in the specified time * range. If no packets match, an empty list will be returned. Expects the specified * AdvertisingPackets to be sorted by timestamp in ascending order (i.e. the oldest timestamp * first)! * * @param advertisingPackets the packets to filter (sorted by timestamp ascending) * @param startTimestamp minimum timestamp, inclusive * @param endTimestamp maximum timestamp, exclusive */ public static <P extends AdvertisingPacket> ArrayList<P> getAdvertisingPacketsBetween(final ArrayList<P> advertisingPackets, long startTimestamp, long endTimestamp) { // check if advertising packets are available if (advertisingPackets.isEmpty()) { return new ArrayList<>(); } P oldestAdvertisingPacket = advertisingPackets.get(0); P latestAdvertisingPacket = advertisingPackets.get(advertisingPackets.size() - 1); // check if the timestamps are out of range if (endTimestamp <= oldestAdvertisingPacket.getTimestamp() || startTimestamp > latestAdvertisingPacket.getTimestamp()) { return new ArrayList<>(); } P midstAdvertisingPacket = advertisingPackets.get(advertisingPackets.size() / 2); // find the index of the first advertising packet with a timestamp // larger than or equal to the specified startTimestamp int startIndex = 0; if (startTimestamp > oldestAdvertisingPacket.getTimestamp()) { // figure out if the start timestamp is before or after the midst advertising packet ListIterator<P> listIterator; if (startTimestamp < midstAdvertisingPacket.getTimestamp()) { // start timestamp is in the first half of advertising packets // start iterating from the beginning listIterator = advertisingPackets.listIterator(); while (listIterator.hasNext()) { if (listIterator.next().getTimestamp() >= startTimestamp) { startIndex = listIterator.previousIndex(); break; } } } else { // start timestamp is in the second half of advertising packets // start iterating from the end listIterator = advertisingPackets.listIterator(advertisingPackets.size()); while (listIterator.hasPrevious()) { if (listIterator.previous().getTimestamp() < startTimestamp) { startIndex = listIterator.nextIndex() + 1; break; } } } } // find the index of the last advertising packet with a timestamp // smaller than the specified endTimestamp int endIndex = advertisingPackets.size(); if (endTimestamp < latestAdvertisingPacket.getTimestamp()) { // figure out if the end timestamp is before or after the midst advertising packet ListIterator<P> listIterator; if (endTimestamp < midstAdvertisingPacket.getTimestamp()) { // end timestamp is in the first half of advertising packets // start iterating from the beginning listIterator = advertisingPackets.listIterator(startIndex); while (listIterator.hasNext()) { if (listIterator.next().getTimestamp() >= endTimestamp) { endIndex = listIterator.previousIndex(); break; } } } else { // end timestamp is in the second half of advertising packets // start iterating from the end listIterator = advertisingPackets.listIterator(advertisingPackets.size()); while (listIterator.hasPrevious()) { if (listIterator.previous().getTimestamp() < endTimestamp) { endIndex = listIterator.nextIndex() + 1; break; } } } } return new ArrayList<>(advertisingPackets.subList(startIndex, endIndex)); } }