diff --git a/src/main/java/edu/nps/moves/dis7/AntennaPattern.java b/src/main/java/edu/nps/moves/dis7/AntennaPattern.java new file mode 100644 index 0000000..3f0f255 --- /dev/null +++ b/src/main/java/edu/nps/moves/dis7/AntennaPattern.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2024, 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.dis7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.Serializable; + +/** + * + * @author fo + */ +public class AntennaPattern extends Object implements Serializable { + + /** + * Constructor + */ + public AntennaPattern() { + } + + public int getMarshalledSize() { + int marshalSize = 0; + + return marshalSize; + } + + public void marshal(DataOutputStream dos) { + try { + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of marshal method + + public void unmarshal(DataInputStream dis) { + try { + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of unmarshal method + + /** + * 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 + * @since ?? + */ + public void marshal(java.nio.ByteBuffer buff) { + } // end of marshal method + + /** + * 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 + * @since ?? + */ + public void unmarshal(java.nio.ByteBuffer buff) { + } // end of unmarshal method + + + /* + * The equals method doesn't always work--mostly it works only on classes that consist only of primitives. Be careful. + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + return equalsImpl(obj); + } + + /** + * Compare all fields that contribute to the state, ignoring transient and + * static fields, for this and the supplied object + * + * @param obj the object to compare to + * @return true if the objects are equal, false otherwise. + */ + public boolean equalsImpl(Object obj) { + boolean ivarsEqual = true; + + if (!(obj instanceof AntennaPattern)) { + return false; + } + + final AntennaPattern rhs = (AntennaPattern) obj; + + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/dis7/AntennaPatternGeneric.java b/src/main/java/edu/nps/moves/dis7/AntennaPatternGeneric.java new file mode 100644 index 0000000..7647626 --- /dev/null +++ b/src/main/java/edu/nps/moves/dis7/AntennaPatternGeneric.java @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2024, 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.dis7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +public class AntennaPatternGeneric extends AntennaPattern { + + List listAntennaPatternOctets = new ArrayList<>(); + + public AntennaPatternGeneric() { + super(); + } + + public int getMarshalledSize() { + int marshalSize = 0; + marshalSize = listAntennaPatternOctets.size(); + int remainder = listAntennaPatternOctets.size() % 8; + if (remainder > 0) { + marshalSize = marshalSize + calculatePaddingByteNr(remainder); + } + return marshalSize; + } + + public List getListAntennaPatternOctets() { + return listAntennaPatternOctets; + } + + public void setListAntennaPatternOctets(List listAntennaPatternOctets) { + this.listAntennaPatternOctets = listAntennaPatternOctets; + } + + public void marshal(DataOutputStream dos) { + try { + Iterator iter = listAntennaPatternOctets.iterator(); + while (iter.hasNext()) { + byte nextByte = iter.next(); + dos.writeByte(nextByte); + } + final int remainder = listAntennaPatternOctets.size() % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + dos.writeByte(0); + } + } + } // end try // end try + catch (Exception e) { + System.out.println(e); + } + } // end of marshal method + + public void unmarshal(DataInputStream dis, int byteCount) { + try { + for (int i = 0; i < byteCount; i++) { + byte nextByte = dis.readByte(); + listAntennaPatternOctets.add(nextByte); + } + final int remainder = byteCount % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + dis.readByte(); + } + } + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of unmarshal method + + /** + * 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 + * @since ?? + */ + public void marshal(java.nio.ByteBuffer buff) { + Iterator iter = listAntennaPatternOctets.iterator(); + while (iter.hasNext()) { + byte nextByte = iter.next(); + buff.put(nextByte); + } + final int remainder = listAntennaPatternOctets.size() % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + buff.put((byte) 0); + } + } + } // end of marshal method + + /** + * 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 + * @since ?? + */ + public void unmarshal(java.nio.ByteBuffer buff, int byteCount) { + try { + for (int i = 0; i < byteCount; i++) { + byte nextByte = buff.get(); + listAntennaPatternOctets.add(nextByte); + } + final int remainder = byteCount % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + buff.get(); + } + } + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of unmarshal method + + private int calculatePaddingByteNr(final int remainder) { + int paddingByteNr = 0; + switch (remainder) { + case 1: + paddingByteNr = 7; + break; + case 2: + paddingByteNr = 6; + break; + case 3: + paddingByteNr = 5; + break; + case 4: + paddingByteNr = 4; + break; + case 5: + paddingByteNr = 3; + break; + case 6: + paddingByteNr = 2; + break; + case 7: + paddingByteNr = 1; + break; + } + return paddingByteNr; + } + + /* + * The equals method doesn't always work--mostly it works only on classes that consist only of primitives. Be careful. + */ + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + return equalsImpl(obj); + } + + /** + * Compare all fields that contribute to the state, ignoring transient and + * static fields, for this and the supplied object + * + * @param obj the object to compare to + * @return true if the objects are equal, false otherwise. + */ + public boolean equalsImpl(Object obj) { + boolean ivarsEqual = true; + + if (!(obj instanceof AntennaPattern)) { + return false; + } + + final AntennaPatternGeneric rhs = (AntennaPatternGeneric) obj; + + for (int idx = 0; idx < listAntennaPatternOctets.size(); idx++) { + if (!(listAntennaPatternOctets.get(idx).equals(rhs.listAntennaPatternOctets.get(idx)))) { + ivarsEqual = false; + } + } + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/dis7/BeamAntennaPattern.java b/src/main/java/edu/nps/moves/dis7/BeamAntennaPattern.java index b8b4db4..b5501fb 100644 --- a/src/main/java/edu/nps/moves/dis7/BeamAntennaPattern.java +++ b/src/main/java/edu/nps/moves/dis7/BeamAntennaPattern.java @@ -13,7 +13,7 @@ * * @author DMcG */ -public class BeamAntennaPattern extends Object implements Serializable { +public class BeamAntennaPattern extends AntennaPattern { /** * The rotation that transforms the reference coordinate sytem into the beam @@ -65,11 +65,13 @@ public class BeamAntennaPattern extends Object implements Serializable { * Constructor */ public BeamAntennaPattern() { + super(); } public int getMarshalledSize() { int marshalSize = 0; - + + marshalSize = marshalSize + super.getMarshalledSize(); marshalSize = marshalSize + beamDirection.getMarshalledSize(); // beamDirection marshalSize = marshalSize + 4; // azimuthBeamwidth marshalSize = marshalSize + 4; // elevationBeamwidth @@ -166,6 +168,7 @@ public long getPadding3() { public void marshal(DataOutputStream dos) { try { + super.marshal(dos); beamDirection.marshal(dos); dos.writeFloat((float) azimuthBeamwidth); dos.writeFloat((float) elevationBeamwidth); @@ -184,6 +187,7 @@ public void marshal(DataOutputStream dos) { public void unmarshal(DataInputStream dis) { try { + super.unmarshal(dis); beamDirection.unmarshal(dis); azimuthBeamwidth = dis.readFloat(); elevationBeamwidth = dis.readFloat(); @@ -210,6 +214,7 @@ public void unmarshal(DataInputStream dis) { * @since ?? */ public void marshal(java.nio.ByteBuffer buff) { + super.marshal(buff); beamDirection.marshal(buff); buff.putFloat((float) azimuthBeamwidth); buff.putFloat((float) elevationBeamwidth); @@ -231,6 +236,7 @@ public void marshal(java.nio.ByteBuffer buff) { * @since ?? */ public void unmarshal(java.nio.ByteBuffer buff) { + super.unmarshal(buff); beamDirection.unmarshal(buff); azimuthBeamwidth = buff.getFloat(); elevationBeamwidth = buff.getFloat(); diff --git a/src/main/java/edu/nps/moves/dis7/CcttSincgarsModulationParameters.java b/src/main/java/edu/nps/moves/dis7/CcttSincgarsModulationParameters.java new file mode 100644 index 0000000..b1a03d9 --- /dev/null +++ b/src/main/java/edu/nps/moves/dis7/CcttSincgarsModulationParameters.java @@ -0,0 +1,237 @@ +/* + * 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.dis7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * + * @author fo + */ +public class CcttSincgarsModulationParameters extends ModulationParameters { + + // This field shall identify the frequency hopping network + private short fhNetId; + + // This field shall identify the set of frequencies used when creating a hopping pattern. + private short hopSetId; + + //This field shall identify the set of frequencies that are excluded from the hopping pattern. + private short lockoutSetId; + + //This field shall specify whether the radio is starting or continuing a transmission + private short startOfMessage; + + private short reserved; + + //This field shall identify the offset to exercise time in seconds for the clock in the SINCGARS radio. + private int fhSynchronizationTimeOffset; + + //This field shall identify the transmission security key that is used when generating the hopping pattern. + private short transmissionSecurityKey; + + //This field shall specify that the transmission is not subject to propagation loss, interference, comsec or any other form of signal degradation. + private short clearChannel; + + public CcttSincgarsModulationParameters() { + + } + + public int getMarshalledSize() { + int marshalSize = 0; + + marshalSize = super.getMarshalledSize(); + marshalSize = marshalSize + 2;// FH Net ID + marshalSize = marshalSize + 2;// Hop Set Id + marshalSize = marshalSize + 2;// Lockou Set ID + marshalSize = marshalSize + 1;// Start of Message + marshalSize = marshalSize + 1;// Reserved + marshalSize = marshalSize + 4;// FH Synchronization Time Offset + marshalSize = marshalSize + 2;// Transmission Security key + marshalSize = marshalSize + 1;// Clear Channel + + return marshalSize; + } + + public short getFhNetId() { + return fhNetId; + } + + public void setFhNetId(short id) { + fhNetId = id; + } + + public short getHopSetId() { + return hopSetId; + } + + public void setHopSetId(short id) { + hopSetId = id; + } + + public short getLockoutSetId() { + return lockoutSetId; + } + + public void setLockoutSetId(short id) { + lockoutSetId = id; + } + + public short getStartOfMessage() { + return startOfMessage; + } + + public void setStartOfMessage(short som) { + startOfMessage = som; + } + + public short getReserved() { + return reserved; + } + + public void setReserved(short r) { + reserved = r; + } + + public int getFhSynchronizationTimeOffset() { + return fhSynchronizationTimeOffset; + } + + public void setFhSynchronizationTimeOffset(int offSet) { + fhSynchronizationTimeOffset = offSet; + } + + public short getTransmissionSecurityKey() { + return transmissionSecurityKey; + } + + public void setTransmissionSecurityKey(short key) { + transmissionSecurityKey = key; + } + + public short getClearChannel() { + return clearChannel; + } + + public void setClearChannel(short channel) { + clearChannel = channel; + } + + public void marshal(DataOutputStream dos) { + try { + super.marshal(dos); + dos.writeShort((short) fhNetId); + dos.writeShort((short) hopSetId); + dos.writeShort((short) lockoutSetId); + dos.writeByte((byte) startOfMessage); + dos.writeByte((byte) reserved); + dos.writeInt((int) fhSynchronizationTimeOffset); + dos.writeShort((short) transmissionSecurityKey); + dos.writeByte((byte) clearChannel); + } catch (IOException e) { + System.out.println("" + e); + } + } + + public void unmarshal(DataInputStream dis) { + try { + super.unmarshal(dis); + fhNetId = (short) dis.readShort(); + hopSetId = (short) dis.readShort(); + lockoutSetId = (short) dis.readShort(); + startOfMessage = (byte) dis.readByte(); + reserved = (byte) dis.readByte(); + fhSynchronizationTimeOffset = (int) dis.readInt(); + transmissionSecurityKey = (short) dis.readShort(); + clearChannel = (byte) dis.readByte(); + } catch (IOException e) { + System.out.println("" + e); + } + } + + public void marshal(java.nio.ByteBuffer buff) { + super.marshal(buff); + buff.putShort((short) fhNetId); + buff.putShort((short) hopSetId); + buff.putShort((short) lockoutSetId); + buff.put((byte) startOfMessage); + buff.put((byte) reserved); + buff.putInt((int) fhSynchronizationTimeOffset); + buff.putShort((short) transmissionSecurityKey); + buff.put((byte) clearChannel); + } + + public void unmarshal(java.nio.ByteBuffer buff) { + super.unmarshal(buff); + fhNetId = (short) (buff.getShort() & 0xFFFF); + hopSetId = (short) (buff.getShort() & 0xFFFF); + lockoutSetId = (short) (buff.getShort() & 0xFFFF); + startOfMessage = (byte) (buff.get() & 0xFF); + reserved = (byte) (buff.get() & 0xFF); + fhSynchronizationTimeOffset = (int) (buff.getInt() & 0xFFFFFFFF); + transmissionSecurityKey = (short) (buff.getShort() & 0xFFFF); + clearChannel = (short) (buff.get() & 0xFFFF); + } + + public boolean equalsImpl(Object obj) { + boolean ivarsEqual = true; + + if (!(obj instanceof CcttSincgarsModulationParameters)) { + return false; + } + + final CcttSincgarsModulationParameters rhs = (CcttSincgarsModulationParameters) obj; + + if (!(fhNetId == rhs.getFhNetId())) { + ivarsEqual = false; + } + if (!(hopSetId == rhs.getHopSetId())) { + ivarsEqual = false; + } + if (!(lockoutSetId == rhs.getLockoutSetId())) { + ivarsEqual = false; + } + if (!(startOfMessage == rhs.getStartOfMessage())) { + ivarsEqual = false; + } + if (!(reserved == rhs.getReserved())) { + ivarsEqual = false; + } + if (!(fhSynchronizationTimeOffset == rhs.getFhSynchronizationTimeOffset())) { + ivarsEqual = false; + } + if (!(transmissionSecurityKey == rhs.getTransmissionSecurityKey())) { + ivarsEqual = false; + } + if (!(clearChannel == rhs.getClearChannel())) { + ivarsEqual = false; + } + + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/dis7/JtidsMidsModulationParameters.java b/src/main/java/edu/nps/moves/dis7/JtidsMidsModulationParameters.java new file mode 100644 index 0000000..0e2166f --- /dev/null +++ b/src/main/java/edu/nps/moves/dis7/JtidsMidsModulationParameters.java @@ -0,0 +1,178 @@ +/* + * 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.dis7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +/** + * + * @author fo + */ +public class JtidsMidsModulationParameters extends ModulationParameters { + + // Defines the fidelity level to be used (range 0 to 4) + private short timeSlotAllocationMode; + + // Defines the primary mode of operation of the transmitting terminal + private short transmittingTerminalPrimaryMode; + + // Defines the secondary mode of operation of the transmitting terminal + private short transmittingTerminalSecondaryMode; + + // Defines the current synchronization state of the transmitting terminal + private short synchronizationState; + + // Defines net id based on what TSA mode is selected. + private int networkSynchronizationID; + + public JtidsMidsModulationParameters() { + + } + + public int getMarshalledSize() { + int marshalSize = 0; + + marshalSize = super.getMarshalledSize(); + marshalSize = marshalSize + 1;// Time Slot Allocation Mode + marshalSize = marshalSize + 1;// Transmitting Terminal Primary Mode + marshalSize = marshalSize + 1;// Transmitting Terminal Secondary Mode + marshalSize = marshalSize + 1;// Synchronization State + marshalSize = marshalSize + 4;// Network Synchronization ID + return marshalSize; + } + + public short getTimeSlotAllocationMode() { + return timeSlotAllocationMode; + } + + public void setTimeSlotAllocationMode(short mode) { + timeSlotAllocationMode = mode; + } + + public short getTransmittingTerminalPrimaryMode() { + return transmittingTerminalPrimaryMode; + } + + public void setTransmittingTerminalPrimaryMode(short mode) { + transmittingTerminalPrimaryMode = mode; + } + + public short getTransmittingTerminalSecondaryMode() { + return transmittingTerminalSecondaryMode; + } + + public void setTransmittingTerminalSecondaryMode(short mode) { + transmittingTerminalSecondaryMode = mode; + } + + public short getSynchronizationState() { + return synchronizationState; + } + + public void setSynchronizationState(short state) { + synchronizationState = state; + } + + public int getNetworkSynchronizationID() { + return networkSynchronizationID; + } + + public void setNetworkSynchronizationID(int id) { + networkSynchronizationID = id; + } + + public void marshal(DataOutputStream dos) { + try { + super.marshal(dos); + dos.writeByte((byte) timeSlotAllocationMode); + dos.writeByte((byte) transmittingTerminalPrimaryMode); + dos.writeByte((byte) transmittingTerminalSecondaryMode); + dos.writeByte((byte) synchronizationState); + dos.writeInt((int) networkSynchronizationID); + + } catch (IOException e) { + System.out.println("" + e); + } + } + + public void unmarshal(DataInputStream dis) { + try { + super.unmarshal(dis); + timeSlotAllocationMode = (short) dis.readByte(); + transmittingTerminalPrimaryMode = (short) dis.readByte(); + transmittingTerminalSecondaryMode = (short) dis.readByte(); + synchronizationState = (short) dis.readByte(); + networkSynchronizationID = (int) dis.readInt(); + } catch (IOException e) { + System.out.println("" + e); + } + } + + public void marshal(java.nio.ByteBuffer buff) { + super.marshal(buff); + buff.put((byte) timeSlotAllocationMode); + buff.put((byte) transmittingTerminalPrimaryMode); + buff.put((byte) transmittingTerminalSecondaryMode); + buff.put((byte) synchronizationState); + buff.putInt((int) networkSynchronizationID); + } + + public void unmarshal(java.nio.ByteBuffer buff) { + super.unmarshal(buff); + timeSlotAllocationMode = (byte) (buff.get() & 0xFF); + transmittingTerminalPrimaryMode = (byte) (buff.get() & 0xFF); + transmittingTerminalSecondaryMode = (byte) (buff.get() & 0xFF); + synchronizationState = (byte) (buff.get() & 0xFF); + networkSynchronizationID = (int) (buff.getInt() & 0xFFFFFFFF); + } + + public boolean equalsImpl(Object obj) { + boolean ivarsEqual = true; + + if (!(obj instanceof JtidsMidsModulationParameters)) { + return false; + } + final JtidsMidsModulationParameters rhs = (JtidsMidsModulationParameters) obj; + if (!(timeSlotAllocationMode == rhs.getTimeSlotAllocationMode())) { + ivarsEqual = false; + } + if (!(transmittingTerminalPrimaryMode == rhs.getTransmittingTerminalPrimaryMode())) { + ivarsEqual = false; + } + if (!(transmittingTerminalSecondaryMode == rhs.getTransmittingTerminalSecondaryMode())) { + ivarsEqual = false; + } + if (!(synchronizationState == rhs.getSynchronizationState())) { + ivarsEqual = false; + } + if (!(networkSynchronizationID == rhs.getNetworkSynchronizationID())) { + ivarsEqual = false; + } + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/dis7/ModulationParametersGeneric.java b/src/main/java/edu/nps/moves/dis7/ModulationParametersGeneric.java new file mode 100644 index 0000000..956c62a --- /dev/null +++ b/src/main/java/edu/nps/moves/dis7/ModulationParametersGeneric.java @@ -0,0 +1,171 @@ +package edu.nps.moves.dis7; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * + * @author fo + */ +public class ModulationParametersGeneric extends ModulationParameters { + + private List modulationParametersList = new ArrayList(); + + public ModulationParametersGeneric() { + } + + public int getMarshalledSize() { + int marshalSize = 0; + + marshalSize = super.getMarshalledSize(); + + marshalSize = marshalSize + modulationParametersList.size() ; + int remainder = modulationParametersList.size() % 8; + if (remainder > 0) { + marshalSize = marshalSize + calculatePaddingByteNr(remainder); + } + return marshalSize; + } + + public List getModulationParametersList() { + return modulationParametersList; + } + + public void setModulationParametersList(List modulationParametersList) { + this.modulationParametersList = modulationParametersList; + } + + private int calculatePaddingByteNr(final int remainder) { + int paddingByteNr = 0; + switch (remainder) { + case 1: + paddingByteNr = 7; + break; + case 2: + paddingByteNr = 6; + break; + case 3: + paddingByteNr = 5; + break; + case 4: + paddingByteNr = 4; + break; + case 5: + paddingByteNr = 3; + break; + case 6: + paddingByteNr = 2; + break; + case 7: + paddingByteNr = 1; + break; + } + return paddingByteNr; + } + + public void marshal(DataOutputStream dos) { + try { + for (int idx = 0; idx < modulationParametersList.size(); idx++) { + byte modulationParameter = modulationParametersList.get(idx); + dos.writeByte(modulationParameter); + } // end of list marshalling + } // end try // end try + catch (Exception e) { + System.out.println(e); + } + } + + public void unmarshal(DataInputStream dis, int byteCount) { + try { + for (int i = 0; i < byteCount; i++) { + byte nextByte = dis.readByte(); + modulationParametersList.add(nextByte); + } + final int remainder = byteCount % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + dis.readByte(); + } + } + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of unmarshal method + + public void marshal(java.nio.ByteBuffer buff) { + Iterator iter = modulationParametersList.iterator(); + while (iter.hasNext()) { + byte nextByte = iter.next(); + buff.put(nextByte); + } + final int remainder = modulationParametersList.size() % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + buff.put((byte) 0); + } + } + } // end of marshal method + + public void unmarshal(java.nio.ByteBuffer buff, int byteCount) { + try { + for (int i = 0; i < byteCount; i++) { + byte nextByte = buff.get(); + modulationParametersList.add(nextByte); + } + final int remainder = byteCount % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + buff.get(); + } + } + } // end try + catch (Exception e) { + System.out.println(e); + } + } // end of unmarshal method + + @Override + public boolean equals(Object obj) { + + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + return equalsImpl(obj); + } + + public boolean equalsImpl(Object obj) { + boolean ivarsEqual = true; + + if (!(obj instanceof ModulationParametersGeneric)) { + return false; + } + + final ModulationParametersGeneric rhs = (ModulationParametersGeneric) obj; + + for (int idx = 0; idx < modulationParametersList.size(); idx++) { + if (!(modulationParametersList.get(idx).equals(rhs.modulationParametersList.get(idx)))) { + ivarsEqual = false; + } + } + return ivarsEqual; + } +} diff --git a/src/main/java/edu/nps/moves/dis7/TransmitterPdu.java b/src/main/java/edu/nps/moves/dis7/TransmitterPdu.java index bf529ac..3b2acd3 100644 --- a/src/main/java/edu/nps/moves/dis7/TransmitterPdu.java +++ b/src/main/java/edu/nps/moves/dis7/TransmitterPdu.java @@ -112,13 +112,18 @@ public class TransmitterPdu extends RadioCommunicationsFamilyPdu implements Seri protected short padding3 = (short) 0; /** - * variable length list of modulation parameters + * modulation parameters */ - protected List< Vector3Float> modulationParametersList = new ArrayList< Vector3Float>(); + protected ModulationParameters modulationParameters = new ModulationParameters(); /** - * variable length list of antenna pattern records + * antenna pattern records */ - protected List< Vector3Float> antennaPatternList = new ArrayList< Vector3Float>(); + protected AntennaPattern antennaPattern = new AntennaPattern(); + + /** + * optional Variable Transmitter Parameters records + */ + protected List variableTransmitterParametersList = new ArrayList<>(); /** * Constructor @@ -150,15 +155,83 @@ public int getMarshalledSize() { marshalSize = marshalSize + 1; // modulationParameterCount marshalSize = marshalSize + 2; // padding2 marshalSize = marshalSize + 1; // padding3 - for (int idx = 0; idx < modulationParametersList.size(); idx++) { - Vector3Float listElement = modulationParametersList.get(idx); - marshalSize = marshalSize + listElement.getMarshalledSize(); - } - for (int idx = 0; idx < antennaPatternList.size(); idx++) { - Vector3Float listElement = antennaPatternList.get(idx); - marshalSize = marshalSize + listElement.getMarshalledSize(); + + int nrOfModulationBytes = 0; + switch (getModulationType().getRadioSystem()) { + case 6:// CCTT SINCGARS + if (modulationParameters instanceof CcttSincgarsModulationParameters) { + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = (CcttSincgarsModulationParameters) modulationParameters; + marshalSize = marshalSize + ccttSincgarsModulationParameters.getMarshalledSize(); + nrOfModulationBytes = nrOfModulationBytes + ccttSincgarsModulationParameters.getMarshalledSize(); + } + break; + case 8:// JTIDS/MIDS + if (modulationParameters instanceof JtidsMidsModulationParameters) { + JtidsMidsModulationParameters jtidsMidsModulationParameters = (JtidsMidsModulationParameters) modulationParameters; + marshalSize = marshalSize + jtidsMidsModulationParameters.getMarshalledSize(); + nrOfModulationBytes = nrOfModulationBytes + jtidsMidsModulationParameters.getMarshalledSize(); + } + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + if (modulationParameters instanceof ModulationParametersGeneric) { + ModulationParametersGeneric modPar = (ModulationParametersGeneric) modulationParameters; + marshalSize = marshalSize + modPar.getMarshalledSize(); + nrOfModulationBytes = nrOfModulationBytes + modPar.getMarshalledSize(); + } + break; } + if (nrOfModulationBytes % 8 > 0) { + int remainder = nrOfModulationBytes % 8; + switch (remainder) { + case 1: + marshalSize = marshalSize + 7; + break; + case 2: + marshalSize = marshalSize + 6; + break; + case 3: + marshalSize = marshalSize + 5; + break; + case 4: + marshalSize = marshalSize + 4; + break; + case 5: + marshalSize = marshalSize + 3; + break; + case 6: + marshalSize = marshalSize + 2; + break; + case 7: + marshalSize = marshalSize + 1; + break; + } + } + switch (antennaPatternType) { + case 1: + if (antennaPattern instanceof BeamAntennaPattern) { + marshalSize = marshalSize + ((BeamAntennaPattern) antennaPattern).getMarshalledSize(); + } + break; + case 6: + break; + default: + if (antennaPattern instanceof AntennaPatternGeneric) { + marshalSize = marshalSize + ((AntennaPatternGeneric) antennaPattern).getMarshalledSize(); + } + break; + } + Iterator iter = variableTransmitterParametersList.iterator(); + while (iter.hasNext()) { + marshalSize = marshalSize + iter.next().getMarshalledSize(); + } return marshalSize; } @@ -235,7 +308,22 @@ public int getAntennaPatternType() { } public int getAntennaPatternCount() { - return (int) antennaPatternList.size(); + int antennaPatternCount = 0; + switch (antennaPatternType) { + case 1: + if (antennaPattern instanceof BeamAntennaPattern) { + antennaPatternCount = ((BeamAntennaPattern) antennaPattern).getMarshalledSize(); + } + break; + case 6: + break; + default: + if (antennaPattern instanceof AntennaPatternGeneric) { + antennaPatternCount = ((AntennaPatternGeneric) antennaPattern).getMarshalledSize(); + } + break; + } + return antennaPatternCount; } /** @@ -298,7 +386,34 @@ public int getCryptoKeyId() { } public short getModulationParameterCount() { - return (short) modulationParametersList.size(); + int modulationParameterOctets = 0; + switch (getModulationType().getRadioSystem()) { + case 6:// CCTT SINCGARS + if (modulationParameters instanceof CcttSincgarsModulationParameters) { + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = (CcttSincgarsModulationParameters) modulationParameters; + modulationParameterOctets = ccttSincgarsModulationParameters.getMarshalledSize(); + } + break; + case 8:// JTIDS/MIDS + if (modulationParameters instanceof JtidsMidsModulationParameters) { + JtidsMidsModulationParameters jtidsMidsModulationParameters = (JtidsMidsModulationParameters) modulationParameters; + modulationParameterOctets = jtidsMidsModulationParameters.getMarshalledSize(); + } + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + if (modulationParameters instanceof ModulationParametersGeneric) { + modulationParameterOctets = ((ModulationParametersGeneric) modulationParameters).getMarshalledSize(); + } + break; + } + return (short) modulationParameterOctets; } /** @@ -328,20 +443,96 @@ public short getPadding3() { return padding3; } - public void setModulationParametersList(List pModulationParametersList) { - modulationParametersList = pModulationParametersList; + /** + * This method sets the modulation parameters associated with the radio + * system type. Modulation parameters can be one of the following records: + *
    + *
  • {@link edu.nps.moves.dis7.CcttSincgarsModulationParameters}: radio + * system = 6
  • + *
  • {@link edu.nps.moves.dis7.JtidsMidsModulationParameters}: radio + * system = 8
  • + *
  • {@link edu.nps.moves.dis7.ModulationParametersGeneric}: others
  • + *
+ * The modulation parameters records above can be set as modulation + * parameters and the + * {@link edu.nps.moves.dis7.ModulationType#setRadioSystem(int)} should be + * set accordingly + * + * + * @param pModulationParameters the modulation parameters to set from the + * list above + */ + public void setModulationParameters(ModulationParameters pModulationParameters) { + modulationParameters = pModulationParameters; + } + + /** + * This method returns the modulation parameters associated with the radio + * system type: {@link edu.nps.moves.dis7.ModulationType#getRadioSystem()} + * and according to this the Modulation parameters can be one of the + * following records: + *
    + *
  • 6: {@link edu.nps.moves.dis7.CcttSincgarsModulationParameters}
  • + *
  • 8: {@link edu.nps.moves.dis7.JtidsMidsModulationParameters}
  • + *
  • other: {@link edu.nps.moves.dis7.ModulationParametersGeneric}
  • + *
+ * The modulation parameters can then be cast as the above records and the + * parameters can then be accessed from that record e.g. + *

+ * ((edu.nps.moves.dis7.CcttSincgarsModulationParameters) + * getModulationParameters()).getStartOfMessage()

+ * + * @return Modulation parameters record from list above + */ + public ModulationParameters getModulationParameters() { + return modulationParameters; } - public List getModulationParametersList() { - return modulationParametersList; + /** + * This method sets the antenna patterns associated with the radio antenna + * pattern type. Antenna patterns can be one of the following records: + *
    + *
  • {@link edu.nps.moves.dis7.BeamAntennaPattern}
  • + *
  • {@link edu.nps.moves.dis7.AntennaPatternGeneric}
  • + *
+ * The antenna patterns above can be set as antenna pattern and the + * {@link edu.nps.moves.dis7.TransmitterPdu#setAntennaPatternType(int)} + * should be set accordingly + * + * @param pAntennaPatternList + */ + public void setAntennaPattern(AntennaPattern pAntennaPatternList) { + antennaPattern = pAntennaPatternList; } - public void setAntennaPatternList(List pAntennaPatternList) { - antennaPatternList = pAntennaPatternList; + /** + * This method returns the antenna pattern associated with the radio antenna + * pattern type: + * {@link edu.nps.moves.dis7.TransmitterPdu#getAntennaPatternType()} and + * according to this the antenna pattern can be one of the following + * records: + *
    + *
  • 1: {@link edu.nps.moves.dis7.BeamAntennaPattern}
  • + *
  • other: {@link edu.nps.moves.dis7.AntennaPatternGeneric}
  • + *
+ * The antenna pattern can then be cast as the above records and the + * parameters can then be accessed from that record e.g. + *

+ * ((edu.nps.moves.dis7.BeamAntennaPattern) + * pdu.getAntennaPattern()).getAzimuthBeamwidth()

+ * + * @return antenna pattern from the list above + */ + public AntennaPattern getAntennaPattern() { + return antennaPattern; } - public List getAntennaPatternList() { - return antennaPatternList; + public List getVariableTransmitterParametersList() { + return variableTransmitterParametersList; + } + + public void setVariableTransmitterParametersList(List variableTransmitterParametersList) { + this.variableTransmitterParametersList = variableTransmitterParametersList; } public void marshal(DataOutputStream dos) { @@ -352,32 +543,101 @@ public void marshal(DataOutputStream dos) { radioEntityType.marshal(dos); dos.writeByte((byte) transmitState); dos.writeByte((byte) inputSource); - dos.writeShort((short) variableTransmitterParameterCount); + dos.writeShort((short) variableTransmitterParametersList.size()); antennaLocation.marshal(dos); relativeAntennaLocation.marshal(dos); dos.writeShort((short) antennaPatternType); - dos.writeShort((short) antennaPatternList.size()); + dos.writeShort((short) getAntennaPatternCount()); dos.writeLong((long) frequency); dos.writeFloat((float) transmitFrequencyBandwidth); dos.writeFloat((float) power); modulationType.marshal(dos); dos.writeShort((short) cryptoSystem); dos.writeShort((short) cryptoKeyId); - dos.writeByte((byte) modulationParametersList.size()); + dos.writeByte((byte) getModulationParameterCount()); dos.writeShort((short) padding2); dos.writeByte((byte) padding3); - for (int idx = 0; idx < modulationParametersList.size(); idx++) { - Vector3Float aVector3Float = modulationParametersList.get(idx); - aVector3Float.marshal(dos); - } // end of list marshalling - - for (int idx = 0; idx < antennaPatternList.size(); idx++) { - Vector3Float aVector3Float = antennaPatternList.get(idx); - aVector3Float.marshal(dos); - } // end of list marshalling + int nrOfModulationBytes = 0; + switch (getModulationType().getRadioSystem()) { + case 6: // CCTT SINCGARS + if (modulationParameters instanceof CcttSincgarsModulationParameters) { + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = (CcttSincgarsModulationParameters) modulationParameters; + ccttSincgarsModulationParameters.marshal(dos); + nrOfModulationBytes = nrOfModulationBytes + ccttSincgarsModulationParameters.getMarshalledSize(); + } + break; + case 8: // JTIDS/MIDS + if (modulationParameters instanceof JtidsMidsModulationParameters) { + JtidsMidsModulationParameters parameterRecord = (JtidsMidsModulationParameters) modulationParameters; + parameterRecord.marshal(dos); + nrOfModulationBytes = nrOfModulationBytes + parameterRecord.getMarshalledSize(); + } + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + if (modulationParameters instanceof ModulationParametersGeneric) { + ModulationParametersGeneric modulationParameter = (ModulationParametersGeneric) modulationParameters; + modulationParameter.marshal(dos); + nrOfModulationBytes += nrOfModulationBytes + modulationParameter.getMarshalledSize(); + break; + } + } + //Add padding up to 64 bit border + if (nrOfModulationBytes % 8 > 0) { + int remainder = 0; + switch (nrOfModulationBytes % 8) { + case 1: + remainder = 7; + break; + case 2: + remainder = 6; + break; + case 3: + remainder = 5; + break; + case 4: + remainder = 4; + break; + case 5: + remainder = 3; + break; + case 6: + remainder = 2; + break; + case 7: + remainder = 1; + break; + } + for (int i = 1; i <= remainder; i++) { + dos.writeByte(0); + } + } + switch (antennaPatternType) { + case 1://Beam + if (antennaPattern instanceof BeamAntennaPattern) { + ((BeamAntennaPattern) antennaPattern).marshal(dos); + } + break; + case 6://Omnidirectional (Toroidal Radiation Pattern) + break; + default://Generic record + if (antennaPattern instanceof AntennaPatternGeneric) { + ((AntennaPatternGeneric) antennaPattern).marshal(dos); + } + break; + } - } // end try + for (int idx = 0; idx < variableTransmitterParametersList.size(); idx++) { + variableTransmitterParametersList.get(idx).marshal(dos); + } + } // end try // end try // end try // end try catch (Exception e) { System.out.println(e); } @@ -406,19 +666,64 @@ public void unmarshal(DataInputStream dis) { modulationParameterCount = (short) dis.readUnsignedByte(); padding2 = (int) dis.readUnsignedShort(); padding3 = (short) dis.readUnsignedByte(); - for (int idx = 0; idx < modulationParameterCount; idx++) { - Vector3Float anX = new Vector3Float(); - anX.unmarshal(dis); - modulationParametersList.add(anX); + int remainder = 0; + int modRecordSize = 0; + switch (getModulationType().getRadioSystem()) { + case 6: // CCTT SINCGARS + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = new CcttSincgarsModulationParameters(); + ccttSincgarsModulationParameters.unmarshal(dis); + modulationParameters = ccttSincgarsModulationParameters; + modRecordSize = 15; + break; + case 8: // JTIDS/MIDS + JtidsMidsModulationParameters jtidsMidsModulationParameters = new JtidsMidsModulationParameters(); + jtidsMidsModulationParameters.unmarshal(dis); + modulationParameters = jtidsMidsModulationParameters; + modRecordSize = 8; + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + ModulationParametersGeneric modPar = new ModulationParametersGeneric(); + modPar.unmarshal(dis, modulationParameterCount); + modulationParameters = modPar; + modRecordSize = modPar.getMarshalledSize(); + break; } - - for (int idx = 0; idx < antennaPatternCount; idx++) { - Vector3Float anX = new Vector3Float(); - anX.unmarshal(dis); - antennaPatternList.add(anX); + //Calculate how many bytes need to be read to end on a 64 bit border + if (modRecordSize % 8 != 0) { + remainder = 8 - (modRecordSize % 8); + for (int i = 1; i <= remainder; i++) { + dis.readByte(); + } } - - } // end try + switch (antennaPatternType) { + case 1://Beam + BeamAntennaPattern beamAntennaPattern = new BeamAntennaPattern(); + beamAntennaPattern.unmarshal(dis); + antennaPattern = beamAntennaPattern; + break; + case 6://Omnidirectional (Toroidal Radiation Pattern) + break; + default://Generic record + AntennaPatternGeneric antennaPatternGeneric = new AntennaPatternGeneric(); + for (int i = 0; i < antennaPatternCount; i++) { + antennaPatternGeneric.unmarshal(dis, antennaPatternCount); + } + antennaPattern = antennaPatternGeneric; + break; + } + for (int idx = 0; idx < variableTransmitterParameterCount; idx++) { + VariableTransmitterParameters varTransPar = new VariableTransmitterParameters(); + varTransPar.unmarshal(dis); + variableTransmitterParametersList.add(varTransPar); + } + } // end try // end try // end try // end try catch (Exception e) { System.out.println(e); } @@ -440,30 +745,90 @@ public void marshal(java.nio.ByteBuffer buff) { radioEntityType.marshal(buff); buff.put((byte) transmitState); buff.put((byte) inputSource); - buff.putShort((short) variableTransmitterParameterCount); + buff.putShort((short) variableTransmitterParametersList.size()); antennaLocation.marshal(buff); relativeAntennaLocation.marshal(buff); buff.putShort((short) antennaPatternType); - buff.putShort((short) antennaPatternList.size()); + buff.putShort((short) getAntennaPatternCount()); buff.putLong((long) frequency); buff.putFloat((float) transmitFrequencyBandwidth); buff.putFloat((float) power); modulationType.marshal(buff); buff.putShort((short) cryptoSystem); buff.putShort((short) cryptoKeyId); - buff.put((byte) modulationParametersList.size()); + buff.put((byte) getModulationParameterCount()); buff.putShort((short) padding2); buff.put((byte) padding3); - for (int idx = 0; idx < modulationParametersList.size(); idx++) { - Vector3Float aVector3Float = (Vector3Float) modulationParametersList.get(idx); - aVector3Float.marshal(buff); - } // end of list marshalling + int nrOfModulationBytes = 0; + switch (getModulationType().getRadioSystem()) { + case 6: // CCTT SINCGARS + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = (CcttSincgarsModulationParameters) modulationParameters; + ccttSincgarsModulationParameters.marshal(buff); + nrOfModulationBytes = nrOfModulationBytes + ccttSincgarsModulationParameters.getMarshalledSize(); + break; + case 8: // JTIDS/MIDS + JtidsMidsModulationParameters parameterRecord = (JtidsMidsModulationParameters) modulationParameters; + parameterRecord.marshal(buff); + nrOfModulationBytes = nrOfModulationBytes + parameterRecord.getMarshalledSize(); + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + ModulationParametersGeneric modulationParameter = (ModulationParametersGeneric) modulationParameters; + modulationParameter.marshal(buff); + nrOfModulationBytes += nrOfModulationBytes + modulationParameter.getMarshalledSize(); + break; + } + //Add padding up to 64 bit border + if (nrOfModulationBytes % 8 > 0) { + int remainder = 0; + switch (nrOfModulationBytes % 8) { + case 1: + remainder = 7; + break; + case 2: + remainder = 6; + break; + case 3: + remainder = 5; + break; + case 4: + remainder = 4; + break; + case 5: + remainder = 3; + break; + case 6: + remainder = 2; + break; + case 7: + remainder = 1; + break; + } + for (int i = 1; i <= remainder; i++) { + buff.put((byte) 0); + } + } + switch (antennaPatternType) { + case 1://Beam + ((BeamAntennaPattern) antennaPattern).marshal(buff); + break; + case 6://Omnidirectional (Toroidal Radiation Pattern) + break; + default://generic record + ((AntennaPatternGeneric) antennaPattern).marshal(buff); + break; + } - for (int idx = 0; idx < antennaPatternList.size(); idx++) { - Vector3Float aVector3Float = (Vector3Float) antennaPatternList.get(idx); - aVector3Float.marshal(buff); - } // end of list marshalling + for (int idx = 0; idx < variableTransmitterParametersList.size(); idx++) { + variableTransmitterParametersList.get(idx).marshal(buff); + } } // end of marshal method @@ -497,16 +862,65 @@ public void unmarshal(java.nio.ByteBuffer buff) { modulationParameterCount = (short) (buff.get() & 0xFF); padding2 = (int) (buff.getShort() & 0xFFFF); padding3 = (short) (buff.get() & 0xFF); - for (int idx = 0; idx < modulationParameterCount; idx++) { - Vector3Float anX = new Vector3Float(); - anX.unmarshal(buff); - modulationParametersList.add(anX); + int remainder = 0; + int modRecordSize = 0; + switch (getModulationType().getRadioSystem()) { + case 6: // CCTT SINCGARS + CcttSincgarsModulationParameters ccttSincgarsModulationParameters = new CcttSincgarsModulationParameters(); + ccttSincgarsModulationParameters.unmarshal(buff); + modulationParameters = ccttSincgarsModulationParameters; + modRecordSize = 15; + break; + case 8: // JTIDS/MIDS + JtidsMidsModulationParameters jtidsMidsModulationParameters = new JtidsMidsModulationParameters(); + jtidsMidsModulationParameters.unmarshal(buff); + modulationParameters = jtidsMidsModulationParameters; + modRecordSize = 8; + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + ModulationParametersGeneric modPar = new ModulationParametersGeneric(); + modPar.unmarshal(buff, modulationParameterCount); + modulationParameters = modPar; + modRecordSize = modPar.getMarshalledSize(); + break; + } + //Calculate how many bytes need to be read to end on a 64 bit border + if (modRecordSize % 8 != 0) { + remainder = 8 - (modRecordSize % 8); + for (int i = 1; i <= remainder; i++) { + buff.get(); + } } - for (int idx = 0; idx < antennaPatternCount; idx++) { - Vector3Float anX = new Vector3Float(); - anX.unmarshal(buff); - antennaPatternList.add(anX); + switch (antennaPatternType) { + case 1://Beam + BeamAntennaPattern beamAntennaPattern = new BeamAntennaPattern(); + beamAntennaPattern.unmarshal(buff); + antennaPattern = beamAntennaPattern; + break; + + case 6://Omnidirectional (Toroidal Radiation Pattern) + break; + default://generic record + AntennaPatternGeneric antennaPatternGeneric = new AntennaPatternGeneric(); + for (int i = 0; i < antennaPatternCount; i++) { + antennaPatternGeneric.unmarshal(buff, antennaPatternCount); + } + antennaPattern = antennaPatternGeneric; + break; + } + + for (int idx = 0; idx < variableTransmitterParameterCount; idx++) { + VariableTransmitterParameters varTransPar = new VariableTransmitterParameters(); + varTransPar.unmarshal(buff); + variableTransmitterParametersList.add(varTransPar); } } // end of unmarshal method @@ -601,18 +1015,50 @@ public boolean equalsImpl(Object obj) { ivarsEqual = false; } - for (int idx = 0; idx < modulationParametersList.size(); idx++) { - if (!(modulationParametersList.get(idx).equals(rhs.modulationParametersList.get(idx)))) { - ivarsEqual = false; - } + switch (getModulationType().getRadioSystem()) { + case 6: // CCTT SINCGARS + if (!(((CcttSincgarsModulationParameters) modulationParameters).equals(((CcttSincgarsModulationParameters) rhs.modulationParameters)))) { + ivarsEqual = false; + } + break; + case 8: // JTIDS/MIDS + if (!(((JtidsMidsModulationParameters) modulationParameters).equals(((JtidsMidsModulationParameters) rhs.modulationParameters)))) { + ivarsEqual = false; + } + break; + case 0: // Other + case 1: // Generic + case 2: // HQ + case 3: // HQII + case 4: // HQIIA + case 5: // SINCGARS + case 7: // EPLRS + default: + if (!((ModulationParametersGeneric) modulationParameters).equals(((ModulationParametersGeneric) rhs.modulationParameters))) { + ivarsEqual = false; + } + break; + } + switch (antennaPatternType) { + case 1: + if (!(((BeamAntennaPattern) antennaPattern).equals(((BeamAntennaPattern) rhs.antennaPattern)))) { + ivarsEqual = false; + } + break; + case 6: + break; + default: + if (!(antennaPattern.equals(rhs.antennaPattern))) { + ivarsEqual = false; + } + break; } - for (int idx = 0; idx < antennaPatternList.size(); idx++) { - if (!(antennaPatternList.get(idx).equals(rhs.antennaPatternList.get(idx)))) { + for (int idx = 0; idx < variableTransmitterParametersList.size(); idx++) { + if (!(variableTransmitterParametersList.get(idx).equals(rhs.variableTransmitterParametersList.get(idx)))) { ivarsEqual = false; } } - return ivarsEqual && super.equalsImpl(rhs); } } // end of class diff --git a/src/main/java/edu/nps/moves/dis7/VariableTransmitterParameters.java b/src/main/java/edu/nps/moves/dis7/VariableTransmitterParameters.java index 84386f2..42e8db0 100644 --- a/src/main/java/edu/nps/moves/dis7/VariableTransmitterParameters.java +++ b/src/main/java/edu/nps/moves/dis7/VariableTransmitterParameters.java @@ -1,6 +1,9 @@ package edu.nps.moves.dis7; import java.io.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; /** * Relates to radios. NOT COMPLETE. Section 6.2.94 @@ -23,6 +26,14 @@ public class VariableTransmitterParameters extends Object implements Serializabl */ protected long recordLength = (long) 4; + /** + * transmitter parameters + */ + protected List recordSpecificFieldsList = new ArrayList<>(); + + private final int RECORD_TYPE_FIELD_SIZE = 4; + + private final int RECORD_LENGTH_FIELD_SIZE = 2; /** * Constructor */ @@ -33,7 +44,12 @@ public int getMarshalledSize() { int marshalSize = 0; marshalSize = marshalSize + 4; // recordType - marshalSize = marshalSize + 4; // recordLength + marshalSize = marshalSize + 2; // recordLength + marshalSize = marshalSize + recordSpecificFieldsList.size(); // recordParameters + int remainder = marshalSize % 8; + if (remainder > 0) { + marshalSize = marshalSize + calculatePaddingByteNr(remainder); + } return marshalSize; } @@ -54,10 +70,59 @@ public long getRecordLength() { return recordLength; } + public List getRecordSpecificFieldsList() { + return recordSpecificFieldsList; + } + + public void setRecordSpecificFieldsList(List recordSpecificFieldsList) { + this.recordSpecificFieldsList = recordSpecificFieldsList; + } + + private int calculatePaddingByteNr(final int remainder) { + int paddingByteNr = 0; + switch (remainder) { + case 1: + paddingByteNr = 7; + break; + case 2: + paddingByteNr = 6; + break; + case 3: + paddingByteNr = 5; + break; + case 4: + paddingByteNr = 4; + break; + case 5: + paddingByteNr = 3; + break; + case 6: + paddingByteNr = 2; + break; + case 7: + paddingByteNr = 1; + break; + } + return paddingByteNr; + } + public void marshal(DataOutputStream dos) { try { dos.writeInt((int) recordType); - dos.writeInt((int) recordLength); + dos.writeShort((int) getMarshalledSize()); + Iterator iter = recordSpecificFieldsList.iterator(); + while (iter.hasNext()) { + byte nextByte = iter.next(); + dos.writeByte(nextByte); + } + final int remainder = (recordSpecificFieldsList.size() + RECORD_TYPE_FIELD_SIZE + RECORD_LENGTH_FIELD_SIZE) % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + dos.writeByte(0); + } + } } // end try catch (Exception e) { System.out.println(e); @@ -67,7 +132,12 @@ public void marshal(DataOutputStream dos) { public void unmarshal(DataInputStream dis) { try { recordType = dis.readInt(); - recordLength = dis.readInt(); + recordLength = dis.readShort(); + final long dataLength = recordLength - RECORD_TYPE_FIELD_SIZE - RECORD_LENGTH_FIELD_SIZE; + for (int i = 0; i < (dataLength); i++) { + byte nextByte = dis.readByte(); + recordSpecificFieldsList.add(nextByte); + } } // end try catch (Exception e) { System.out.println(e); @@ -85,7 +155,20 @@ public void unmarshal(DataInputStream dis) { */ public void marshal(java.nio.ByteBuffer buff) { buff.putInt((int) recordType); - buff.putInt((int) recordLength); + buff.putShort((short) getMarshalledSize()); + Iterator iter = recordSpecificFieldsList.iterator(); + while (iter.hasNext()) { + byte nextByte = iter.next(); + buff.put(nextByte); + } + final int remainder = recordSpecificFieldsList.size() % 8; + if (remainder > 0) { + int paddingByteNr = 0; + paddingByteNr = calculatePaddingByteNr(remainder); + for (int i = 0; i < paddingByteNr; i++) { + buff.put((byte) 0); + } + } } // end of marshal method /** @@ -98,7 +181,12 @@ public void marshal(java.nio.ByteBuffer buff) { */ public void unmarshal(java.nio.ByteBuffer buff) { recordType = buff.getInt(); - recordLength = buff.getInt(); + recordLength = buff.getShort(); + final long dataLength = recordLength - RECORD_TYPE_FIELD_SIZE - RECORD_LENGTH_FIELD_SIZE; + for (int i = 0; i < dataLength; i++) { + byte nextByte = buff.get(); + recordSpecificFieldsList.add(nextByte); + } } // end of unmarshal method @@ -146,6 +234,12 @@ public boolean equalsImpl(Object obj) { ivarsEqual = false; } + for (int idx = 0; idx < recordSpecificFieldsList.size(); idx++) { + if (!(recordSpecificFieldsList.get(idx).equals(rhs.recordSpecificFieldsList.get(idx)))) { + ivarsEqual = false; + } + } + return ivarsEqual; } } // end of class diff --git a/src/test/java/edu/nps/moves/dis7/TransmitterPduTest.java b/src/test/java/edu/nps/moves/dis7/TransmitterPduTest.java new file mode 100644 index 0000000..171e547 --- /dev/null +++ b/src/test/java/edu/nps/moves/dis7/TransmitterPduTest.java @@ -0,0 +1,131 @@ +package edu.nps.moves.dis7; + +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 + */ +public class TransmitterPduTest { + + public TransmitterPduTest() { + } + + @BeforeClass + public static void setUpClass() { + } + + @AfterClass + public static void tearDownClass() { + } + + @Before + public void setUp() { + } + + @After + public void tearDown() { + } + + @Test + public void marshal() { + TransmitterPdu tpdu = new TransmitterPdu(); + ModulationParametersGeneric mpg = new ModulationParametersGeneric(); + tpdu.setModulationParameters(mpg); + AntennaPatternGeneric apg = new AntennaPatternGeneric(); + tpdu.setAntennaPattern(apg); + byte[] buffer = tpdu.marshal(); + + assertEquals(buffer.length, tpdu.getLength()); + } + + @Test + public void unmarshal() throws IOException { + PduFactory factory = new PduFactory(); + Pdu pdu = factory.createPdu(edu.nps.moves.dis7.PduFileLoader.load("TransmitterPdu_VariableTransmitterParameters.raw")); + assertEquals(7, pdu.getProtocolVersion()); + assertEquals(1, pdu.getExerciseID()); + assertEquals(25, pdu.getPduType()); + assertEquals(4, pdu.getProtocolFamily()); + assertEquals(208, pdu.getLength()); + assertEquals(0, pdu.getPduStatus()); + assertEquals(0, pdu.getPadding()); + + TransmitterPdu tpdu = (TransmitterPdu) pdu; + + // Modulation Type + assertEquals(2, tpdu.getModulationType().getSpreadSpectrum()); + assertEquals(1, tpdu.getModulationType().getMajorModulation()); + assertEquals(10, tpdu.getModulationType().getDetail()); + assertEquals(1, tpdu.getModulationType().getRadioSystem()); + + assertEquals(55555555, tpdu.getFrequency()); + + // Modulation Parameters + assertEquals(8, tpdu.getModulationParameterCount()); + assertEquals(1, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(0)); + assertEquals(2, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(1)); + assertEquals(3, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(2)); + assertEquals(4, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(3)); + assertEquals(5, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(4)); + assertEquals(6, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(5)); + assertEquals(7, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(6)); + assertEquals(8, (byte)((ModulationParametersGeneric)tpdu.getModulationParameters()).getModulationParametersList().get(7)); + + + + // Antenna Pattern + assertEquals(55.5, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getAzimuthBeamwidth(), 0.001); + final EulerAngles beamDirection = ((BeamAntennaPattern) tpdu.getAntennaPattern()).getBeamDirection(); + assertEquals(3.0, beamDirection.getPhi(), 0.001); + assertEquals(2.0, beamDirection.getTheta(), 0.001); + assertEquals(1.0, beamDirection.getPsi(), 0.001); + assertEquals(54.5, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getElevationBeamwidth(), 0.001); + assertEquals(53.5, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getEx(), 0.001); + assertEquals(52.5, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getEz(), 0.001); + assertEquals(51.5, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getPhase(), 0.001); + assertEquals(2, ((BeamAntennaPattern) tpdu.getAntennaPattern()).getReferenceSystem()); + + + // Variable transmitter parameters + assertEquals(3, tpdu.getVariableTransmitterParameterCount()); + + assertEquals(2, tpdu.getVariableTransmitterParametersList().get(0).getRecordType()); + assertEquals(16, tpdu.getVariableTransmitterParametersList().get(0).getRecordLength()); + assertEquals(1, (byte) tpdu.getVariableTransmitterParametersList().get(0).getRecordSpecificFieldsList().get(0)); + assertEquals(2, (byte) tpdu.getVariableTransmitterParametersList().get(0).getRecordSpecificFieldsList().get(1)); + assertEquals(3, (byte) tpdu.getVariableTransmitterParametersList().get(0).getRecordSpecificFieldsList().get(2)); + assertEquals(4, (byte) tpdu.getVariableTransmitterParametersList().get(0).getRecordSpecificFieldsList().get(3)); + assertEquals(5, (byte) tpdu.getVariableTransmitterParametersList().get(0).getRecordSpecificFieldsList().get(4)); + + assertEquals(3, tpdu.getVariableTransmitterParametersList().get(1).getRecordType()); + assertEquals(24, tpdu.getVariableTransmitterParametersList().get(1).getRecordLength()); + assertEquals(1, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(0)); + assertEquals(2, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(1)); + assertEquals(3, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(2)); + assertEquals(4, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(3)); + assertEquals(5, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(4)); + assertEquals(6, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(5)); + assertEquals(7, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(6)); + assertEquals(8, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(7)); + assertEquals(9, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(8)); + assertEquals(10, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(9)); + assertEquals(12, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(10)); + assertEquals(13, (byte) tpdu.getVariableTransmitterParametersList().get(1).getRecordSpecificFieldsList().get(11)); + + + assertEquals(2, tpdu.getVariableTransmitterParametersList().get(2).getRecordType()); + assertEquals(16, tpdu.getVariableTransmitterParametersList().get(2).getRecordLength()); + assertEquals(1, (byte) tpdu.getVariableTransmitterParametersList().get(2).getRecordSpecificFieldsList().get(0)); + assertEquals(2, (byte) tpdu.getVariableTransmitterParametersList().get(2).getRecordSpecificFieldsList().get(1)); + assertEquals(3, (byte) tpdu.getVariableTransmitterParametersList().get(2).getRecordSpecificFieldsList().get(2)); + assertEquals(4, (byte) tpdu.getVariableTransmitterParametersList().get(2).getRecordSpecificFieldsList().get(3)); + assertEquals(5, (byte) tpdu.getVariableTransmitterParametersList().get(2).getRecordSpecificFieldsList().get(4)); + } +} diff --git a/src/test/resources/edu/nps/moves/dis7/TransmitterPdu_VariableTransmitterParameters.raw b/src/test/resources/edu/nps/moves/dis7/TransmitterPdu_VariableTransmitterParameters.raw new file mode 100644 index 0000000..98cbc8b Binary files /dev/null and b/src/test/resources/edu/nps/moves/dis7/TransmitterPdu_VariableTransmitterParameters.raw differ