package dk.silverbullet.telemed.device.monica; import android.util.Log; import dk.silverbullet.telemed.device.monica.packet.CBlockMessage; import dk.silverbullet.telemed.device.monica.packet.FetalHeightAndSignalToNoise; import dk.silverbullet.telemed.device.monica.packet.MmMessage; import dk.silverbullet.telemed.device.monica.packet.MonicaMessage; import dk.silverbullet.telemed.questionnaire.node.monica.MonicaDeviceCallback; import dk.silverbullet.telemed.utils.Util; import java.util.Date; import java.util.LinkedList; import java.util.List; public class MessageProcessor { private static final int MINIMUM_ONTIME_COUNT = 2; private static final String TAG = Util.getTag(MessageProcessor.class); private final MonicaDeviceCallback monicaCallback; private int ontimeMessageCount = 0; private Date lastOntimeMessage; private final List<MonicaMessage> msgBuffer = new LinkedList<MonicaMessage>(); private int count; private boolean mhrReceived = false; private Date startTime; private long lastMessageTime; private long lastTimeDiff = 0; private boolean shortPauseExpected = false; private boolean longPauseObserved; public MessageProcessor(MonicaDeviceCallback monicaCallback) { this.monicaCallback = monicaCallback; } public void process(CBlockMessage msg) throws MonicaSamplesMissingException { if (!mhrReceived) { mhrReceived = isMhrPresent(msg); if (!mhrReceived) return; // Ignore until MHR values received! } count++; msgBuffer.add(msg); long timeSpan = msg.getReadTime().getTime() - lastMessageTime; if (timeSpan > 1500 && timeSpan < 2500 && !shortPauseExpected) { Log.d(TAG, "Long message timing: " + timeSpan); shortPauseExpected = true; longPauseObserved = true; } else if (timeSpan < 100 && shortPauseExpected && longPauseObserved) { Log.d(TAG, "Short message timing: " + timeSpan); longPauseObserved = false; shortPauseExpected = false; ontimeMessageCount++; Log.d(TAG, "On time messages: " + ontimeMessageCount); if (ontimeMessageCount >= MINIMUM_ONTIME_COUNT) { processBuffer(); lastOntimeMessage = msg.getReadTime(); } } else { Log.d(TAG, "Message timing: " + timeSpan + ", expected " + (shortPauseExpected ? "10" : "2000") + " ms"); longPauseObserved = false; ontimeMessageCount = 0; shortPauseExpected = timeSpan > 1000; } monicaCallback.updateProgress(count, monicaCallback.getSampleTimeMinutes() * 60); lastMessageTime = msg.getReadTime().getTime(); } private boolean isMhrPresent(CBlockMessage msg) { for (float mhr : msg.getMHR()) { if (mhr != 0F) return true; } return false; } private void processBuffer() throws MonicaSamplesMissingException { Date currentTime = null; CBlockMessage firstCBlock = null; int cbCount = 0; for (MonicaMessage m : msgBuffer) { if (m instanceof CBlockMessage) { cbCount++; if (firstCBlock == null) { firstCBlock = (CBlockMessage) m; } currentTime = m.getReadTime(); } } if (startTime == null) { // No messages added yet! startTime = firstCBlock.getReadTime(); lastOntimeMessage = startTime; monicaCallback.setStartTimeValue(startTime); } else if (count % 2 != 0) { throw new MonicaSamplesMissingException("Message lost! count=" + count); } else { long timeDiff = startTime.getTime() - currentTime.getTime() + 1000 * (count - 2); long delta = timeDiff - lastTimeDiff; Log.d(TAG, "timeDiff: " + timeDiff + " delta: " + delta + " count: " + count + " (buffered:" + cbCount + ")"); if (delta < -2000 || delta > 2000) { throw new MonicaSamplesMissingException("timeDiff: " + timeDiff + " delta: " + delta + " count: " + count + " (buffered: " + cbCount + "/" + msgBuffer.size() + ")"); } lastTimeDiff = timeDiff; } flushMessageBuffer(); } public void flushMessageBuffer() { Log.d(TAG, "Flushing " + msgBuffer.size() + " messages"); long estimatedTime = lastOntimeMessage == null ? 0 : lastOntimeMessage.getTime(); for (MonicaMessage m : msgBuffer) { if (m instanceof CBlockMessage) { estimatedTime += 1000; CBlockMessage cb = (CBlockMessage) m; monicaCallback.addSamples(cb.getMHR(), cb.getFHR1(), cb.getQFHR1(), cb.getTOCO(), cb.getReadTime()); } else if (m instanceof MmMessage) { monicaCallback.addSignal(new Date(estimatedTime + 500)); } else if (m instanceof FetalHeightAndSignalToNoise) { FetalHeightAndSignalToNoise msg = (FetalHeightAndSignalToNoise) m; monicaCallback.addFetalHeight(msg.getFetalHeight()); monicaCallback.addSignalToNoise(msg.getFetalHeight()); } else { Log.w(TAG, "Unknown message type: " + m); } } msgBuffer.clear(); } public void process(MmMessage msg) { if (mhrReceived) { msgBuffer.add(msg); } } public void process(FetalHeightAndSignalToNoise msg) { if (mhrReceived) { msgBuffer.add(msg); } } }