1010 ModulationParametersRecord ,
1111 UnknownRadio ,
1212 UnknownAntennaPattern ,
13+ EulerAngles ,
14+ BeamAntennaPattern ,
15+ GenericRadio ,
16+ SimpleIntercomRadio ,
17+ BasicHaveQuickMP ,
18+ CCTTSincgarsMP ,
19+ VariableTransmitterParametersRecord ,
20+ HighFidelityHAVEQUICKRadio ,
21+ UnknownVariableTransmitterParameters ,
1322)
1423from .stream import DataInputStream , DataOutputStream
1524from .types import (
@@ -678,34 +687,6 @@ def parse(self, inputStream):
678687 self .stationNumber = inputStream .read_unsigned_short ()
679688
680689
681- class EulerAngles :
682- """Section 6.2.33
683-
684- Three floating point values representing an orientation, psi, theta,
685- and phi, aka the euler angles, in radians.
686- """
687-
688- def __init__ (self ,
689- psi : float32 = 0.0 ,
690- theta : float32 = 0.0 ,
691- phi : float32 = 0.0 ): # in radians
692- self .psi = psi
693- self .theta = theta
694- self .phi = phi
695-
696- def serialize (self , outputStream ):
697- """serialize the class"""
698- outputStream .write_float (self .psi )
699- outputStream .write_float (self .theta )
700- outputStream .write_float (self .phi )
701-
702- def parse (self , inputStream ):
703- """Parse a message. This may recursively call embedded objects."""
704- self .psi = inputStream .read_float ()
705- self .theta = inputStream .read_float ()
706- self .phi = inputStream .read_float ()
707-
708-
709690class DirectedEnergyPrecisionAimpoint :
710691 """Section 6.2.20.3
711692
@@ -843,63 +824,6 @@ def parse(self, inputStream):
843824 self .padding = inputStream .read_unsigned_byte ()
844825
845826
846- class BeamAntennaPattern :
847- """Section 6.2.9.2
848-
849- Used when the antenna pattern type field has a value of 1. Specifies the
850- direction, pattern, and polarization of radiation from an antenna.
851- """
852-
853- def __init__ (self ,
854- beamDirection : "EulerAngles | None" = None ,
855- azimuthBeamwidth : float32 = 0.0 , # in radians
856- elevationBeamwidth : float32 = 0.0 , # in radians
857- referenceSystem : enum8 = 0 , # [UID 168]
858- ez : float32 = 0.0 ,
859- ex : float32 = 0.0 ,
860- phase : float32 = 0.0 ): # in radians
861- self .beamDirection = EulerAngles ()
862- """The rotation that transforms the reference coordinate sytem into the beam coordinate system. Either world coordinates or entity coordinates may be used as the reference coordinate system, as specified by the reference system field of the antenna pattern record."""
863- self .azimuthBeamwidth = azimuthBeamwidth
864- self .elevationBeamwidth = elevationBeamwidth
865- self .referenceSystem = referenceSystem
866- self .padding1 : uint8 = 0
867- self .padding2 : uint16 = 0
868- self .ez = ez
869- """This field shall specify the magnitude of the Z-component (in beam coordinates) of the Electrical field at some arbitrary single point in the main beam and in the far field of the antenna."""
870- self .ex = ex
871- """This field shall specify the magnitude of the X-component (in beam coordinates) of the Electrical field at some arbitrary single point in the main beam and in the far field of the antenna."""
872- self .phase = phase
873- """This field shall specify the phase angle between EZ and EX in radians. If fully omni-directional antenna is modeled using beam pattern type one, the omni-directional antenna shall be represented by beam direction Euler angles psi, theta, and phi of zero, an azimuth beamwidth of 2PI, and an elevation beamwidth of PI"""
874- self .padding3 : uint32 = 0
875-
876- def serialize (self , outputStream ):
877- """serialize the class"""
878- self .beamDirection .serialize (outputStream )
879- outputStream .write_float (self .azimuthBeamwidth )
880- outputStream .write_float (self .elevationBeamwidth )
881- outputStream .write_unsigned_byte (self .referenceSystem )
882- outputStream .write_unsigned_byte (self .padding1 )
883- outputStream .write_unsigned_short (self .padding2 )
884- outputStream .write_float (self .ez )
885- outputStream .write_float (self .ex )
886- outputStream .write_float (self .phase )
887- outputStream .write_unsigned_int (self .padding3 )
888-
889- def parse (self , inputStream ):
890- """Parse a message. This may recursively call embedded objects."""
891- self .beamDirection .parse (inputStream )
892- self .azimuthBeamwidth = inputStream .read_float ()
893- self .elevationBeamwidth = inputStream .read_float ()
894- self .referenceSystem = inputStream .read_unsigned_byte ()
895- self .padding1 = inputStream .read_unsigned_byte ()
896- self .padding2 = inputStream .read_unsigned_short ()
897- self .ez = inputStream .read_float ()
898- self .ex = inputStream .read_float ()
899- self .phase = inputStream .read_float ()
900- self .padding3 = inputStream .read_unsigned_int ()
901-
902-
903827class AttachedParts :
904828 """Section 6.2.93.3
905829
@@ -938,36 +862,6 @@ def parse(self, inputStream):
938862 self .parameterValue = inputStream .read_long ()
939863
940864
941- class VariableTransmitterParameters :
942- """Section 6.2.94
943-
944- Relates to radios. NOT COMPLETE.
945- """
946-
947- def __init__ (self , recordType : enum32 = 0 , data : bytes = b"" ):
948- self .recordType = recordType # [UID 66] Variable Parameter Record Type
949- self .data = data
950-
951- def marshalledSize (self ) -> int :
952- return 6 + len (self .data )
953-
954- @property
955- def recordLength (self ) -> uint16 :
956- return self .marshalledSize ()
957-
958- def serialize (self , outputStream : DataOutputStream ) -> None :
959- """serialize the class"""
960- outputStream .write_uint32 (self .recordType )
961- outputStream .write_uint16 (self .recordLength )
962- outputStream .write_bytes (self .data )
963-
964- def parse (self , inputStream : DataInputStream ) -> None :
965- """Parse a message. This may recursively call embedded objects."""
966- self .recordType = inputStream .read_uint32 ()
967- recordLength = inputStream .read_uint16 ()
968- self .data = inputStream .read_bytes (recordLength )
969-
970-
971865class Attribute :
972866 """Section 6.2.10.
973867
@@ -5411,11 +5305,11 @@ def parse(self, inputStream):
54115305
54125306
54135307class TransmitterPdu (RadioCommunicationsFamilyPdu ):
5414- """Section 7.7.2
5308+ """7.7.2 Transmitter PDU
54155309
54165310 Detailed information about a radio transmitter. This PDU requires manually
54175311 written code to complete, since the modulation parameters are of variable
5418- length. UNFINISHED
5312+ length.
54195313 """
54205314 pduType : enum8 = 25 # [UID 4]
54215315
@@ -5436,7 +5330,7 @@ def __init__(self,
54365330 cryptoKeyId : struct16 = 0 , # See Table 175
54375331 modulationParameters : ModulationParametersRecord | None = None ,
54385332 antennaPattern : AntennaPatternRecord | None = None ,
5439- variableTransmitterParameters : Sequence [VariableTransmitterParameters ] | None = None ):
5333+ variableTransmitterParameters : Sequence [VariableTransmitterParametersRecord ] | None = None ):
54405334 super (TransmitterPdu , self ).__init__ ()
54415335 self .radioReferenceID = radioReferenceID or EntityID ()
54425336 """ID of the entity that is the source of the communication"""
@@ -5459,7 +5353,11 @@ def __init__(self,
54595353 self .padding3 = 0
54605354 self .modulationParameters = modulationParameters
54615355 self .antennaPattern = antennaPattern
5462- self .variableTransmitterParameters = variableTransmitterParameters or []
5356+ self .variableTransmitterParameters = (
5357+ list (variableTransmitterParameters )
5358+ if variableTransmitterParameters
5359+ else []
5360+ )
54635361
54645362 @property
54655363 def antennaPatternLength (self ) -> uint16 :
@@ -5542,23 +5440,50 @@ def parse(self, inputStream: DataInputStream) -> None:
55425440
55435441 ## Modulation Parameters
55445442 if modulationParametersLength > 0 :
5545- radio = UnknownRadio ()
5546- radio .parse (inputStream , bytelength = modulationParametersLength )
5443+ if self .modulationType .radioSystem == 1 : # Generic | Simple Intercom
5444+ if self .modulationType .majorModulation == 0 :
5445+ radio = SimpleIntercomRadio ()
5446+ else :
5447+ radio = GenericRadio ()
5448+ radio .parse (inputStream )
5449+ elif self .modulationType .radioSystem in (2 , 3 , 4 ): # HAVE QUICK I | II | HAVE QUICK IIA
5450+ radio = BasicHaveQuickMP ()
5451+ radio .parse (inputStream )
5452+ elif self .modulationType .radioSystem == 6 : # CCTT SINCGARS
5453+ radio = CCTTSincgarsMP ()
5454+ radio .parse (inputStream )
5455+ else : # Other | Unknown
5456+ radio = UnknownRadio ()
5457+ radio .parse (inputStream , bytelength = modulationParametersLength )
55475458 self .modulationParameters = radio
55485459 else :
55495460 self .modulationParameters = None
55505461
55515462 ## Antenna Pattern
55525463 if antennaPatternLength > 0 :
5553- self .antennaPattern = UnknownAntennaPattern ()
5554- self .antennaPattern .parse (
5555- inputStream ,
5556- bytelength = antennaPatternLength
5557- )
5464+ if self .antennaPatternType == 1 :
5465+ self .antennaPattern = BeamAntennaPattern ()
5466+ self .antennaPattern .parse (inputStream )
5467+ else :
5468+ self .antennaPattern = UnknownAntennaPattern ()
5469+ self .antennaPattern .parse (
5470+ inputStream ,
5471+ bytelength = antennaPatternLength
5472+ )
55585473 else :
55595474 self .antennaPattern = None
5560-
5561-
5475+
5476+ ## TODO: Variable Transmitter Parameters
5477+ for _ in range (0 , variableTransmitterParameterCount ):
5478+ recordType = inputStream .read_uint32 ()
5479+ if recordType == 3000 : # High Fidelity HAVE QUICK/SATURN Radio
5480+ vtp = HighFidelityHAVEQUICKRadio ()
5481+ vtp .parse (inputStream )
5482+ else : # Unknown VTP record type
5483+ vtp = UnknownVariableTransmitterParameters ()
5484+ vtp .recordType = recordType
5485+ vtp .parse (inputStream )
5486+ self .variableTransmitterParameters .append (vtp )
55625487
55635488
55645489class ElectromagneticEmissionsPdu (DistributedEmissionsFamilyPdu ):
0 commit comments