package pl.llp.aircasting.sensor.bioharness; import pl.llp.aircasting.model.events.SensorEvent; import pl.llp.aircasting.sensor.TimestampTracker; import pl.llp.aircasting.util.Pair; import com.google.common.eventbus.EventBus; import java.io.ByteArrayOutputStream; import static pl.llp.aircasting.sensor.bioharness.BioharnessPacketReader.buildBioharnessEvent; public class BioharnessPacketReader { private final TimestampTracker timestampTracker = new TimestampTracker(); private final EventBus eventBus; private final RtoRPacketReader rToRReader; public BioharnessPacketReader(EventBus eventBus) { this.eventBus = eventBus; this.rToRReader = new RtoRPacketReader(eventBus, timestampTracker); } public Integer tryReading(ByteArrayOutputStream input) { Pair<PacketType, Integer> typeAndLength; byte[] data = input.toByteArray(); for (int offset = 0; offset < data.length; offset++) { typeAndLength = PacketType.decide(data, offset); PacketType packetType = typeAndLength.getFirst(); if (!packetType.isValid()) { continue; } Integer length = typeAndLength.getSecond(); if (data.length - (length + offset) < 0) { continue; } switch (packetType) { case SummaryPacket: { SummaryPacket packet = new SummaryPacket(data, offset); long timeStamp = timestampTracker.getLocalTimestamp(packet.getTimeStamp()); postHeartRate(packet, timeStamp); postBreathing(packet); postCoreTemperature(packet); postActivity(packet); postAcceleration(packet); break; } case RtoRPacket: { rToRReader.process(data, offset); break; } case ECGPacket: { break; } } return offset + length; } return 0; } void postRtoR(RtoRPacket packet, long timeStamp) { int[] samples = packet.getSamples(); int previous = Integer.MIN_VALUE; for (int i = 0; i < samples.length; i++) { int value = samples[i]; int absValue = Math.abs(value); if (0 < absValue && absValue <= 3000 && absValue != previous) { postRtoREvent(absValue, timeStamp + i * 56); } previous = absValue; } } void postRtoREvent(int value, long timeStamp) { SensorEvent event = buildBioharnessEvent("R to R", "RTR", "milliseconds", "ms", 400, 800, 1200, 1600, 2000, value, timeStamp); eventBus.post(event); } private void postCoreTemperature(SummaryPacket packet) { if (packet.isCoreTemperatureReliable()) { double coreTemperature = packet.getCoreTemperature(); SensorEvent event = buildBioharnessEvent("Core Temperature", "CT", "degrees Celsius", "C", 36, 37, 38, 39, 40, coreTemperature); eventBus.post(event); } } private void postAcceleration(SummaryPacket packet) { SensorEvent event = buildBioharnessEvent("Peak Acceleration", "PkA", "standard gravity", ".01g", 0, 100, 200, 300, 400, packet .getPeakAcceleration()); eventBus.post(event); } private void postActivity(SummaryPacket packet) { if (packet.isActivityReliable()) { double value = packet.getActivity(); SensorEvent event = buildBioharnessEvent("Activity Level", "AL", "Vector Magnitude Units", "VMU", 0, 50, 100, 150, 200, value); eventBus.post(event); } } void postHeartRate(SummaryPacket packet, long timestamp) { SensorEvent event; if (packet.isHeartRateReliable()) { int heartRate = packet.getHeartRate(); event = buildBioharnessEvent("Heart Rate", "HR", "beats per minute", "bpm", 40, 85, 130, 175, 220, heartRate); eventBus.post(event); } if (packet.isHeartRateVariabilityReliable()) { int variability = packet.getHeartRateVariability(); event = buildBioharnessEvent("Heart Rate Variability", "HRV", "milliseconds", "ms", 0, 70, 140, 210, 280, variability, timestamp); eventBus.post(event); } } void postBreathing(SummaryPacket packet) { if (packet.isRespirationRateReliable()) { double respirationRate = packet.getRespirationRate(); SensorEvent event = buildBioharnessEvent("Breathing Rate", "BR", "breaths per minute", "bpm", 0, 30, 60, 90, 120, respirationRate); eventBus.post(event); } } SensorEvent buildBioharnessEvent(String longName, String shortName, String unitLong, String unitShort, int thresholdVeryLow, int thresholdLow, int thresholdMedium, int thresholdHigh, int thresholdVeryHigh, double value ) { return new SensorEvent("BioHarness3", "BioHarness3:" + shortName, longName, shortName, unitLong, unitShort, thresholdVeryLow, thresholdLow, thresholdMedium, thresholdHigh, thresholdVeryHigh, value); } static SensorEvent buildBioharnessEvent(String longName, String shortName, String unitLong, String unitShort, int thresholdVeryLow, int thresholdLow, int thresholdMedium, int thresholdHigh, int thresholdVeryHigh, double value, long timeStamp ) { return new SensorEvent("BioHarness3", "BioHarness3:" + shortName, longName, shortName, unitLong, unitShort, thresholdVeryLow, thresholdLow, thresholdMedium, thresholdHigh, thresholdVeryHigh, value, timeStamp); } } class RtoRPacketReader { private final RepeatedValueTracker repeatedTracker = new RepeatedValueTracker(); private final EventBus eventBus; private final TimestampTracker timestampTracker; public RtoRPacketReader(EventBus eventBus, TimestampTracker timestampTracker) { this.eventBus = eventBus; this.timestampTracker = timestampTracker; } void postRtoR(RtoRPacket packet, long timeStamp) { int[] samples = packet.getSamples(); for (int i = 0; i < samples.length; i++) { int value = samples[i]; if (-3000 <= value && value <= 3000) { if(repeatedTracker.isNew(value)) { int absValue = Math.abs(value); postRtoREvent(absValue, timeStamp + i * 56); } } } } void postRtoREvent(int value, long timeStamp) { SensorEvent event = buildBioharnessEvent("R to R", "RTR", "milliseconds", "ms", 400, 800, 1200, 1600, 2000, value, timeStamp); eventBus.post(event); } public void process(byte[] data, int offset) { RtoRPacket packet = new RtoRPacket(data, offset); long timeStamp = timestampTracker.getLocalTimestamp(packet.getTimeStamp()); postRtoR(packet, timeStamp); } } class RepeatedValueTracker { boolean first = true; int previous = 0; boolean isNew(int value) { if (first) { first = false; previous = value; return true; } boolean result = previous != value; previous = value; return result; } }