diff --git a/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer1Pdu.java b/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer1Pdu.java index 43ab7a9..2287110 100644 --- a/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer1Pdu.java +++ b/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer1Pdu.java @@ -13,6 +13,9 @@ */ public class IffAtcNavAidsLayer1Pdu extends DistributedEmissionsFamilyPdu implements Serializable { + private static final int LAYER_PRESENT = 4; + + private static final int LAYER_NOT_PRESENT = 0; /** * ID of the entity that is the source of the emissions */ @@ -42,7 +45,17 @@ public class IffAtcNavAidsLayer1Pdu extends DistributedEmissionsFamilyPdu implem /** * fundamental parameters */ - protected IffFundamentalData fundamentalParameters = new IffFundamentalData(); + protected IffFundamentalData fundamentalData = new IffFundamentalData(); + + /** + * layer 2 value: 0 = not present, 1 = present + */ + protected int layer2Value = 0; + + /** + * layer 2 part of an IFF/ATC/NAVAIDS PDU + */ + protected IffAtcNavAidsLayer2Pdu layer2 = null; /** * Constructor @@ -60,8 +73,10 @@ public int getMarshalledSize() { marshalSize = marshalSize + location.getMarshalledSize(); // location marshalSize = marshalSize + systemID.getMarshalledSize(); // systemID marshalSize = marshalSize + 2; // pad2 - marshalSize = marshalSize + fundamentalParameters.getMarshalledSize(); // fundamentalParameters - + marshalSize = marshalSize + fundamentalData.getMarshalledSize(); // fundamentalData + if ((this.getLayer2Value() & LAYER_PRESENT) == LAYER_PRESENT) { + marshalSize = marshalSize + layer2.getMarshalledSize(); + } return marshalSize; } @@ -105,12 +120,39 @@ public int getPad2() { return pad2; } - public void setFundamentalParameters(IffFundamentalData pFundamentalParameters) { - fundamentalParameters = pFundamentalParameters; + public void setFundamentalData(IffFundamentalData pFundamentalData) { + fundamentalData = pFundamentalData; } - public IffFundamentalData getFundamentalParameters() { - return fundamentalParameters; + public IffFundamentalData getFundamentalData() { + return fundamentalData; + } + + public void setLayer2Value(int pLayer2Value) { + short newInformationLayer; + this.layer2Value = pLayer2Value << 2; + newInformationLayer = (short) (this.getFundamentalData().getInformationLayers() & 0xFB); + newInformationLayer = (short) (newInformationLayer | this.layer2Value); + this.getFundamentalData().setInformationLayers(newInformationLayer); + } + + public int getLayer2Value() { + this.layer2Value = this.getFundamentalData().getInformationLayers() & 0x4; // Mask out everything except bit 2 + return this.layer2Value; + } + + public void setIffAtcNavAidsLayer2(IffAtcNavAidsLayer2Pdu pLayer2) { + this.layer2 = pLayer2; + short data = getFundamentalData().getInformationLayers(); + data = (short) (data | (1 << 2)); //set bit 2 indicating that layer 2 is present + getFundamentalData().setInformationLayers(data); + + this.layer2.getLayerHeader().setLayerNumber((short) 2); + this.layer2.getLayerHeader().setLayerSpecificInformaiton((short) 0); + } + + public IffAtcNavAidsLayer2Pdu getIffAtcNavAidsLayer2() { + return this.layer2; } /** @@ -129,7 +171,10 @@ public void marshal(java.nio.ByteBuffer buff) { location.marshal(buff); systemID.marshal(buff); buff.putShort((short) pad2); - fundamentalParameters.marshal(buff); + fundamentalData.marshal(buff); + if ((this.getLayer2Value() & LAYER_PRESENT) == LAYER_PRESENT) { + layer2.marshal(buff); + } } // end of marshal method /** @@ -148,7 +193,12 @@ public void unmarshal(java.nio.ByteBuffer buff) { location.unmarshal(buff); systemID.unmarshal(buff); pad2 = (int) (buff.getShort() & 0xFFFF); - fundamentalParameters.unmarshal(buff); + fundamentalData.unmarshal(buff); + + if ((this.getLayer2Value() & LAYER_PRESENT) == LAYER_PRESENT) { + layer2 = new IffAtcNavAidsLayer2Pdu(); + layer2.unmarshal(buff); + } } // end of unmarshal method @@ -198,10 +248,16 @@ public boolean equalsImpl(Object obj) { if (!(pad2 == rhs.pad2)) { ivarsEqual = false; } - if (!(fundamentalParameters.equals(rhs.fundamentalParameters))) { + if (!(fundamentalData.equals(rhs.fundamentalData))) { ivarsEqual = false; } + if ((this.getLayer2Value() & LAYER_PRESENT) == LAYER_PRESENT) { + if (!(layer2.equals(rhs.layer2))) { + ivarsEqual = false; + } + } + return ivarsEqual && super.equalsImpl(rhs); } } // end of class diff --git a/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer2Pdu.java b/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer2Pdu.java index 0a14498..308bdd3 100644 --- a/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer2Pdu.java +++ b/src/main/java/edu/nps/moves/dis/IffAtcNavAidsLayer2Pdu.java @@ -29,7 +29,7 @@ public class IffAtcNavAidsLayer2Pdu extends IffAtcNavAidsLayer1Pdu implements Se /** * Secondary operational data, 5.2.57 */ - protected BeamData secondaryOperationalData = new BeamData(); + protected SecondaryOperationalData secondaryOperationalData = new SecondaryOperationalData(); /** * variable length list of fundamental parameters. ^^^This is wrong @@ -45,7 +45,6 @@ public IffAtcNavAidsLayer2Pdu() { public int getMarshalledSize() { int marshalSize = 0; - marshalSize = super.getMarshalledSize(); marshalSize = marshalSize + layerHeader.getMarshalledSize(); // layerHeader marshalSize = marshalSize + beamData.getMarshalledSize(); // beamData marshalSize = marshalSize + secondaryOperationalData.getMarshalledSize(); // secondaryOperationalData @@ -73,11 +72,11 @@ public BeamData getBeamData() { return beamData; } - public void setSecondaryOperationalData(BeamData pSecondaryOperationalData) { + public void setSecondaryOperationalData(SecondaryOperationalData pSecondaryOperationalData) { secondaryOperationalData = pSecondaryOperationalData; } - public BeamData getSecondaryOperationalData() { + public SecondaryOperationalData getSecondaryOperationalData() { return secondaryOperationalData; } @@ -99,9 +98,10 @@ public List getFundamentalIffParameters() { * @since ?? */ public void marshal(java.nio.ByteBuffer buff) { - super.marshal(buff); + layerHeader.setLength(32 + (24 * fundamentalIffParameters.size())); layerHeader.marshal(buff); beamData.marshal(buff); + secondaryOperationalData.setNumberofFundamentalParameterDataSets(fundamentalIffParameters.size()); secondaryOperationalData.marshal(buff); for (int idx = 0; idx < fundamentalIffParameters.size(); idx++) { @@ -120,12 +120,11 @@ public void marshal(java.nio.ByteBuffer buff) { * @since ?? */ public void unmarshal(java.nio.ByteBuffer buff) { - super.unmarshal(buff); layerHeader.unmarshal(buff); beamData.unmarshal(buff); secondaryOperationalData.unmarshal(buff); - for (int idx = 0; idx < pad2; idx++) { + for (int idx = 0; idx < secondaryOperationalData.getNumberofFundamentalParameterDataSets(); idx++) { FundamentalParameterDataIff anX = new FundamentalParameterDataIff(); anX.unmarshal(buff); fundamentalIffParameters.add(anX); diff --git a/src/main/java/edu/nps/moves/dis/IffFundamentalData.java b/src/main/java/edu/nps/moves/dis/IffFundamentalData.java index 1cf2299..64c2d48 100644 --- a/src/main/java/edu/nps/moves/dis/IffFundamentalData.java +++ b/src/main/java/edu/nps/moves/dis/IffFundamentalData.java @@ -178,6 +178,7 @@ public int getParameter6() { public void marshal(java.nio.ByteBuffer buff) { buff.put((byte) systemStatus); buff.put((byte) alternateParameter4); + informationLayers = (short) (informationLayers | (1 << 1)); //inform that layer 1 is present buff.put((byte) informationLayers); buff.put((byte) modifier); buff.putShort((short) parameter1); diff --git a/src/main/java/edu/nps/moves/dis/SecondaryOperationalData.java b/src/main/java/edu/nps/moves/dis/SecondaryOperationalData.java new file mode 100644 index 0000000..ea5002b --- /dev/null +++ b/src/main/java/edu/nps/moves/dis/SecondaryOperationalData.java @@ -0,0 +1,166 @@ +/* + * Copyright (c) 2022, The Moves Institute + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package edu.nps.moves.dis; + +import java.io.DataInput; +import java.io.DataOutput; +import java.nio.ByteBuffer; + +/** + * + * @author fo-ifad + */ +public class SecondaryOperationalData { + + /** + * Additional characteristics of the IFF/ATC/NAVAIDS emitter system + */ + protected short parameter1; + + /** + * Additional characteristics of the IFF/ATC/NAVAIDS emitter system + */ + protected short parameter2; + + /** + * Number of Fundamental Parameter data sets + */ + protected int numberofFundamentalParameterDataSets; + + public SecondaryOperationalData() { + + } + + public int getMarshalledSize() { + + int marshalSize = 0; + + marshalSize = marshalSize + 1; // parameter1 + marshalSize = marshalSize + 1; // parameter2 + marshalSize = marshalSize + 2; // numberofFundamentalParameterDataSets + + return marshalSize; + } + + public void setParameter1(short pParameter1) { + this.parameter1 = pParameter1; + } + + public short getParameter1() { + return this.parameter1; + } + + public void setParameter2(short pParameter2) { + this.parameter2 = pParameter2; + } + + public short getParameter2() { + return this.parameter2; + } + + public void setNumberofFundamentalParameterDataSets(int pNumberofFundamentalParameterDataSets) { + this.numberofFundamentalParameterDataSets = pNumberofFundamentalParameterDataSets; + } + + public int getNumberofFundamentalParameterDataSets() { + return this.numberofFundamentalParameterDataSets; + } + + public void marshal(DataOutput dos) { + try { + dos.writeByte((byte) parameter1); + dos.writeByte((byte) parameter2); + dos.writeShort((short) numberofFundamentalParameterDataSets); + } catch (Exception e) { + System.out.println(e); + } + } + + public void unmarshal(DataInput dis) { + + try { + this.parameter1 = (short) dis.readUnsignedByte(); + this.parameter2 = (short) dis.readUnsignedByte(); + this.numberofFundamentalParameterDataSets = (int) dis.readUnsignedShort(); + } catch (Exception e) { + System.out.println(e); + } + } + + /** + * Packs a Pdu into the ByteBuffer. + * + * @throws java.nio.BufferOverflowException if buff is too small + * @throws java.nio.ReadOnlyBufferException if buff is read only + * @see java.nio.ByteBuffer + * @param buff The ByteBuffer at the position to begin writing + */ + public void marshal(ByteBuffer buff) { + + buff.put((byte) parameter1); + buff.put((byte) parameter2); + buff.putShort((short) numberofFundamentalParameterDataSets); + } + + /** + * Unpacks a Pdu from the underlying data. + * + * @throws java.nio.BufferUnderflowException if buff is too small + * @see java.nio.ByteBuffer + * @param buff The ByteBuffer at the position to begin reading + */ + public void unmarshal(ByteBuffer buff) { + + this.parameter1 = (short) (buff.get() & 0xFF); + this.parameter2 = (short) (buff.get() & 0xFF); + this.numberofFundamentalParameterDataSets = (int) (buff.getShort() & 0xFFFF); + } + + /** + * The equals method doesn't always work--mostly it works only on classes + * that consist only of primitives. Be careful. + */ + public boolean equals(SecondaryOperationalData rhs) { + + boolean ivarsEqual = true; + + if (rhs.getClass() != this.getClass()) { + return false; + } + + if (!(parameter1 == rhs.parameter1)) { + ivarsEqual = false; + } + if (!(parameter2 == rhs.parameter2)) { + ivarsEqual = false; + } + if (!(numberofFundamentalParameterDataSets == rhs.numberofFundamentalParameterDataSets)) { + ivarsEqual = false; + } + + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/disutil/PduFactory.java b/src/main/java/edu/nps/moves/disutil/PduFactory.java index adf9062..d1aa728 100644 --- a/src/main/java/edu/nps/moves/disutil/PduFactory.java +++ b/src/main/java/edu/nps/moves/disutil/PduFactory.java @@ -348,7 +348,9 @@ public Pdu createPdu(java.nio.ByteBuffer buff) { case ENTITY_STATE_UPDATE: aPdu = new EntityStateUpdatePdu(); break; - + case IFF_ATC_NAVAIDS: + aPdu = new IffAtcNavAidsLayer1Pdu(); + break; default: logger.log(Level.INFO, "PDU not implemented. Type = " + pduType + "\n"); if (pduTypeEnum != null) { diff --git a/src/test/java/edu/nps/moves/dis/IffAtcNavAidsPduTest.java b/src/test/java/edu/nps/moves/dis/IffAtcNavAidsPduTest.java new file mode 100644 index 0000000..376c736 --- /dev/null +++ b/src/test/java/edu/nps/moves/dis/IffAtcNavAidsPduTest.java @@ -0,0 +1,82 @@ +package edu.nps.moves.dis; + +import edu.nps.moves.disutil.PduFactory; +import java.io.IOException; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import static org.junit.Assert.*; + +/** + * + * @author fo-ifad + */ +public class IffAtcNavAidsPduTest { + + public IffAtcNavAidsPduTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void unmarshal() throws IOException { + PduFactory factory = new PduFactory(); + Pdu pdu = factory.createPdu(PduFileLoader.load("IFF_ATC_NAVAIDS_PDU.raw")); + + // Header + assertEquals(6, pdu.getProtocolVersion()); + assertEquals(1, pdu.getExerciseID()); + assertEquals(28, pdu.getPduType()); + assertEquals(6, pdu.getProtocolFamily()); + //TODO assertEquals((long) ???, aPdu.getTimestamp()); + assertEquals(60, pdu.getLength()); + assertEquals(0, pdu.getPadding()); + + IffAtcNavAidsLayer1Pdu iffPdu = (IffAtcNavAidsLayer1Pdu) pdu; + //IFF PDU + //Emitting entityid + assertEquals(1, iffPdu.getEmittingEntityId().getSite()); + assertEquals(3001, iffPdu.getEmittingEntityId().getApplication()); + assertEquals(17, iffPdu.getEmittingEntityId().getEntity()); + //Event id + assertEquals(1, iffPdu.getEventID().getSite()); + assertEquals(3001, iffPdu.getEventID().getApplication()); + assertEquals(2, iffPdu.getEventID().getEventNumber()); + //Location with respect to entity + assertEquals(0f, iffPdu.getLocation().getX(), 0.001); + assertEquals(0f, iffPdu.getLocation().getY(), 0.001); + assertEquals(0f, iffPdu.getLocation().getZ(), 0.001); + //System ID + assertEquals(1, iffPdu.getSystemID().getSystemType()); + assertEquals(7, iffPdu.getSystemID().getSystemName()); + assertEquals(0, iffPdu.getSystemID().getSystemMode()); + //Fundamental operational status + assertEquals(0x01, iffPdu.getFundamentalData().getSystemStatus()); + assertEquals(1, iffPdu.getFundamentalData().getAlternateParameter4()); + assertEquals(2, iffPdu.getFundamentalData().getInformationLayers()); + assertEquals(14, iffPdu.getFundamentalData().getModifier()); + assertEquals(8255, iffPdu.getFundamentalData().getParameter1()); + assertEquals(12287, iffPdu.getFundamentalData().getParameter2()); + assertEquals(12287, iffPdu.getFundamentalData().getParameter3()); + assertEquals(23, iffPdu.getFundamentalData().getParameter4()); + assertEquals(12287, iffPdu.getFundamentalData().getParameter5()); + assertEquals(8192, iffPdu.getFundamentalData().getParameter6()); + + } +} diff --git a/src/test/resources/edu/nps/moves/dis/IFF_ATC_NAVAIDS_PDU.raw b/src/test/resources/edu/nps/moves/dis/IFF_ATC_NAVAIDS_PDU.raw new file mode 100644 index 0000000..2a60ae2 Binary files /dev/null and b/src/test/resources/edu/nps/moves/dis/IFF_ATC_NAVAIDS_PDU.raw differ