package com.dronecontrol.droneapi.navdata; import com.dronecontrol.droneapi.data.NavData; import com.dronecontrol.droneapi.data.NavDataState; import com.dronecontrol.droneapi.data.enums.ControlAlgorithm; import static com.google.common.base.Preconditions.checkState; import static com.dronecontrol.droneapi.helpers.BinaryDataHelper.flagSet; import static com.dronecontrol.droneapi.helpers.BinaryDataHelper.getFloatValue; import static com.dronecontrol.droneapi.helpers.BinaryDataHelper.getIntValue; import static com.dronecontrol.droneapi.helpers.BinaryDataHelper.getUnsignedByteValue; public class NavigationDataDecoder { private final static int CORRECT_HEADER = 0x55667788; private static final int NAV_DATA_TAG = 0x0000; private static final int NAV_DATA_TAG_CHECKSUM = 0xFFFF; private int currentOffset; private byte[] buffer; private int bufferLength; private NavData currentNavData; public NavData getNavDataFrom(byte[] buffer, int bufferLength) { initializeFields(buffer, bufferLength); processNavDataHeader(buffer); currentOffset += 16; while (currentOffset < bufferLength) { int tag = getIntValue(buffer, currentOffset, 2); int length = getIntValue(buffer, currentOffset + 2, 2); currentOffset += 4; checkState(length != 0, "Got a zero length tag"); processTag(tag, length); currentOffset += length - 4; } return currentNavData; } private void initializeFields(byte[] buffer, int bufferLength) { this.buffer = buffer; this.bufferLength = bufferLength; this.currentOffset = 0; this.currentNavData = new NavData(); } private void processNavDataHeader(byte[] buffer) { checkState(isHeaderCorrect(), "The header is incorrect"); int stateFlags = getIntValue(buffer, currentOffset + 4, 4); int sequenceNumber = getIntValue(buffer, currentOffset + 8, 4); currentNavData.setSequenceNumber(sequenceNumber); currentNavData.setState(getNavDataState(stateFlags)); } private boolean isHeaderCorrect() { int header = getIntValue(buffer, 0, 4); return header == CORRECT_HEADER; } public NavDataState getNavDataState(int stateFlags) { NavDataState state = new NavDataState(); state.setFlying(flagSet(stateFlags, 0)); state.setVideoEnabled(flagSet(stateFlags, 1)); state.setVisionEnabled(flagSet(stateFlags, 2)); state.setControlAlgorithm(flagSet(stateFlags, 3) ? ControlAlgorithm.ANGULAR_SPEED_CONTROL : ControlAlgorithm.EULER_ANGLES_CONTROL); state.setAltitudeControlActive(flagSet(stateFlags, 4)); state.setUserFeedbackOn(flagSet(stateFlags, 5)); state.setControlReceived(flagSet(stateFlags, 6)); state.setTrimReceived(flagSet(stateFlags, 7)); state.setTrimRunning(flagSet(stateFlags, 8)); state.setTrimSucceeded(flagSet(stateFlags, 9)); state.setNavDataDemoOnly(flagSet(stateFlags, 10)); state.setNavDataBootstrap(flagSet(stateFlags, 11)); state.setMotorsDown(flagSet(stateFlags, 12)); state.setGyrometersDown(flagSet(stateFlags, 14)); state.setBatteryTooLow(flagSet(stateFlags, 15)); state.setBatteryTooHigh(flagSet(stateFlags, 16)); state.setTimerElapsed(flagSet(stateFlags, 17)); state.setNotEnoughPower(flagSet(stateFlags, 18)); state.setAnglesOutOfRange(flagSet(stateFlags, 19)); state.setTooMuchWind(flagSet(stateFlags, 20)); state.setUltrasonicSensorDeaf(flagSet(stateFlags, 21)); state.setCutoutSystemDetected(flagSet(stateFlags, 22)); state.setPicVersionNumberOK(flagSet(stateFlags, 23)); state.setAtCodedThreadOn(flagSet(stateFlags, 24)); state.setNavDataThreadOn(flagSet(stateFlags, 25)); state.setVideoThreadOn(flagSet(stateFlags, 26)); state.setAcquisitionThreadOn(flagSet(stateFlags, 27)); state.setControlWatchdogDelayed(flagSet(stateFlags, 28)); state.setAdcWatchdogDelayed(flagSet(stateFlags, 29)); state.setCommunicationProblemOccurred(flagSet(stateFlags, 30)); state.setEmergency(flagSet(stateFlags, 31)); return state; } private void processTag(int tag, int length) { if (tag == NAV_DATA_TAG) { currentNavData.setOnlyHeaderPresent(false); processNavData(); } else if (tag == NAV_DATA_TAG_CHECKSUM) { processCheckSum(length); } } private void processNavData() { currentNavData.setBatteryLevel(getIntValue(buffer, currentOffset + 4, 4)); currentNavData.setPitch(getFloatValue(buffer, currentOffset + 8, 4) / 1000); currentNavData.setRoll(getFloatValue(buffer, currentOffset + 12, 4) / 1000); currentNavData.setYaw(getFloatValue(buffer, currentOffset + 16, 4) / 1000); currentNavData.setAltitude((float) getIntValue(buffer, currentOffset + 20, 4) / 1000.0f); currentNavData.setSpeedX(getFloatValue(buffer, currentOffset + 24, 4)); currentNavData.setSpeedY(getFloatValue(buffer, currentOffset + 28, 4)); currentNavData.setSpeedZ(getFloatValue(buffer, currentOffset + 32, 4)); } private void processCheckSum(int checkSumLength) { int checksum = calculateCheckSumForReceivedBytes(checkSumLength); int checkSumReceived = getIntValue(buffer, currentOffset, 4); checkState(checksum == checkSumReceived, "Wrong checksum calculated"); } private int calculateCheckSumForReceivedBytes(int checkSumLength) { int checksum = 0; for (int index = 0; index < bufferLength - checkSumLength; index++) { checksum += getUnsignedByteValue(buffer[index]); } return checksum; } }