package de.graeb.adsbsniffer; import android.os.Handler; import android.os.Message; import android.util.Log; import java.util.Date; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import de.graeb.adsbsniffer.adbsreceiver.Packet; /** * Class calculating statistics over the received packets * * Calculates flights, updates statistics of the database * * @author markus */ public class RecordingStatistics { public static final int INTERVAL_STATUS = 1000; private final UpdateFlightsHandler updateFlightsHandler; private int packetsReceived; private int packetsReceivedInterval; private final ConcurrentHashMap<String, Entry> flights; private final DatabaseHelper recordingDb; private final int timeoutFlight; RecordingStatistics(int timeoutFlight, DatabaseHelper recordingDb) { this.recordingDb = recordingDb; this.timeoutFlight = timeoutFlight; packetsReceived = 0; flights = new ConcurrentHashMap<>(); updateFlightsHandler = new UpdateFlightsHandler(); updateFlightsHandler.sendEmptyMessageDelayed(0, INTERVAL_STATUS); } /** * @param packet received data packet * @return the id the flight */ public long add(Packet packet) { Entry entry; if (!flights.containsKey(packet.icao24)) { // create new flight long id = recordingDb.storeFlight(new Date(), packet.icao24); entry = new Entry(id); flights.put(packet.icao24, entry); } else { entry = flights.get(packet.icao24); } entry.time = new Date(); if (packet.isAdsb) { entry.packetsAdsb++; } else { entry.packetsModeS++; } packetsReceived++; return entry.id; } /** * Get the count of received Mode-S packets * @return count */ public int getCountMessages() { return packetsReceived; } /** * Get the rate of all received packets (of the last second) * @return rate in packet/second */ public double getRate() { return ((double) packetsReceivedInterval) / (((double) INTERVAL_STATUS) / 1000); } /** * Get current known icao24 * @return list of icao24 */ public String[] getIcao24s() { Set<String> strings = flights.keySet(); return strings.toArray(new String[strings.size()]); } public class Entry { final long id; Date time; int packetsAdsb = 0; int packetsModeS = 0; private Entry(long id) { this.id = id; } public int getPacketsModeS() { return packetsModeS; } public int getPacketsAdsb() { return packetsAdsb; } public Date getLastPacket() { return time; } } public Entry getEntry(String icao24) { return flights.get(icao24); } /** * Write the data to the database and stop handler */ void writeBack () { // stop handler updateFlightsHandler.removeMessages(0); // write last received message to flights.last for (Entry entry : flights.values()) { recordingDb.updateFlight(entry.id, entry.time); recordingDb.storeFlightState(entry.id, new Date(), entry.packetsAdsb, entry.packetsModeS); } } public int getTimeoutFlight() { return timeoutFlight; } private int getPacketsReceivedLast = 0; /** * Periodically run to update the flights list * also updates the database */ private class UpdateFlightsHandler extends Handler { @Override public void handleMessage(Message message) { // calculate packets in this interval packetsReceivedInterval = packetsReceived - getPacketsReceivedLast; getPacketsReceivedLast = packetsReceived; // store flight states for (Entry entry : flights.values()) { if (recordingDb != null) { recordingDb.storeFlightState(entry.id, new Date(), entry.packetsAdsb, entry.packetsModeS); } } // update flights for (Map.Entry<String, Entry> mapEntry : flights.entrySet()) { Date threshold = new Date(); threshold.setTime(threshold.getTime() - timeoutFlight * 1000 * 60); Entry entry = mapEntry.getValue(); if (entry.time.before(threshold)) { // timeout of flight if (recordingDb != null) { recordingDb.updateFlight(entry.id, entry.time); } flights.remove(mapEntry.getKey()); Log.d("Recording.UpdateFlights", "removed flight " + mapEntry.getKey() + " seen " + entry.time); } } sendEmptyMessageDelayed(0, INTERVAL_STATUS); } } }