GithubHelp home page GithubHelp logo

open-dis / open-dis-python Goto Github PK

View Code? Open in Web Editor NEW
48.0 9.0 31.0 1.04 MB

Python implementation of the IEEE-1278.1 Distributed Interactive Simulation (DIS) application protocol v7

License: BSD 2-Clause "Simplified" License

Python 100.00%
dis python protocol

open-dis-python's Introduction

open-dis-python

Build Status PyPI Version

A Python 3 implementation of the Distributed Interactive Simulation (DIS) 7 standard. Initially generated by xmlpg.

Library installation

From source:

pip install .

For developers of this library (This installs a symlink to the sources so they can be edited and referenced in tests and examples without a reinstall):

pip install -e .

Run examples

Run a receiver:

cd examples
python3 dis_receiver.py

In another terminal, run the sender:

python3 dis_sender.py

You should also see the traffic on the net in Wireshark on your localhost interface.

Press Ctrl+\ to stop the process.

Documentation

You can auto generate API docs from the project source code:

pip install pdoc
pdoc --html --html-dir docs opendis

The docs will be generated in the docs/opendis folder.

Poetry setup

  1. poetry install or poetry update
  2. poetry run python examples/dis_receiver.py or poetry shell && python examples/dis_receiver.py

open-dis-python's People

Contributors

brutzman avatar connermarzen avatar igor3d avatar jason-mckinney avatar leif81 avatar marcdtheking avatar mcgredonps avatar ngjunsiang avatar peteblanchard avatar ricklentz avatar savagesmc avatar scottrbrtsn avatar setherith avatar zpshank avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

open-dis-python's Issues

Parenthesis Wrong in dis7.py

Missing parenthesis on read_* function calls

Use read_([0-9a-z_]+)(?=\r\n) regex to find (with windows line endings)

Lines found:

  • 245
  • 250
  • 365
  • 698
  • 740
  • 1228
  • 1430
  • 1496
  • 2692
  • 3027
  • 6017
  • 6028

SignalPdu Not Packing Data Correctly

Hi!

It looks like the SignalPdu is not packing data correctly (found at https://github.com/open-dis/open-dis-python/blob/master/opendis/dis7.py#L7070).

In my understanding, the data field of the SignalPdu is supposed to be an array of bytes more or less, based on the code in the init and parse methods. However, the serialize method for the data field implies that each object in the list should have a "serialize" method, which a standard byte would not.

My recommended change would be to change https://github.com/open-dis/open-dis-python/blob/master/opendis/dis7.py#L7107
from

anObj.serialize(outputStream)

to

outputStream.write_byte(anObj)

not an issue but a question surrounding performance

awesome library guys and i am enjoying the flexibility that you have offered in higher level programming languages in python/chsarp.

is there any performance metrics between using python vs using c++ for this tool? i am currently developing a poc dis packet converter for testing purposes using this tool (which has been excellent.). my concern is throughput and latency - i will be testing the latency down the line but i was enquiring about if you have any known data/ advice about best methods for focusing on low latency tool when using this? - for development process i would rather stick with python/csharp opposed to c++ if i could but if there is a large impact then i may have to go down that route.

thanks guys

Redundant fields cause serialization/parsing errors

The SimulationManagementFamilyPdu class defines two fields:

  • originatingEntityIdD
  • receivingEntityID

The following subclasses of SimulationManagementFamilyPdu

  • AcknowledgePdu
  • ActionResponsePdu
  • ActionRequestPdu
  • CreateEntityPdu
  • RemoveEntityPdu
  • StartResumePdu
  • StopFreezePdu

also define two redundant fields:

  • originatingID
  • receivingID

This means that the Originating ID and Receiving ID fields are serialized and parsed twice for these 7 classes. This results in serialization errors when parsing PDUs from external systems, which only serialize these fields once per PDU.

Notes:
The following classes do not define the redundant fields, and inherit from SimulationManagementFamilyPdu without issue (in this regard):

  • CommentPdu
  • DataPdu
  • DataQueryPdu
  • EventReportPdu
  • SetDataPdu

Will this become a Pip package?

Are there any plans to make this a package installable via pip with versioned releases to help reliant projects pickup new fixes?

Divide by zero in RangeCoordinates.py

This change to open-dis-python will enable connectivity between open-dis-javascript (node-disnetworkclient) and open-dis-python samples (previously, p was 0).

I have senders and receivers working in both languages, interoperable? Perhaps.

diff --git a/opendis/RangeCoordinates.py b/opendis/RangeCoordinates.py
index f28b4f2..5e24188 100644
--- a/opendis/RangeCoordinates.py
+++ b/opendis/RangeCoordinates.py
@@ -166,7 +166,7 @@ class GPS:
         #Initialize the variables to calculate lat and alt
         alt = 0
         N = self.wgs84.a
-        p = sqrt(x**2 + y**2)
+        p = sqrt(x**2 + y**2) + 0.001
         lat = 0
         previousLat = 90
         #Iterate until tolerance is reached

Fixes this error:

coderextreme@coderextreme-Kubuntu20:~/open-dis-python$ python3 examples/dis_receiver.py
Listening for DIS on UDP socket 1194
Traceback (most recent call last):
  File "examples/dis_receiver.py", line 39, in <module>
    recv()
  File "examples/dis_receiver.py", line 32, in recv
    lla = gps.ecef2lla(loc)
  File "/home/coderextreme/open-dis-python/opendis/RangeCoordinates.py", line 176, in ecef2lla
    lat = atan((z + self.wgs84.e**2 * N * sinLat) / p)
ZeroDivisionError: float division by zero

DataPdu Not finished - needs example

I am struggling to find an example of how to use a DataPdu. The nature of python makes it difficult to read your code and decipher how to create a simple DataPdu to send a simple integer as the variable length data.

This may be because DataPdu is unfinished. Could you

  1. Provide an example of creating a DataPdu with a variable length record to send an integer as the payload
  2. Finish the DataPdu section?

Example does not function as it intended

I went into detail on this issue on my StackOverflow question regarding the topic, which can be found here. At the time of this issue report, it has not been answered.

Any idea why the examples would be behaving this way? Is there some change that could be made to prevent them from happening in the future?

The StackOverflow question:

I am attempting to get the open-dis python package running correctly on my machine. I am running Python 3.8.

Using pip, I compile the package from it's source as so: pip install .

After that, as instructed in the documentation. I run python dis_receiver.py

I am immediately met with this error:

Created UDP socket 3001
Traceback (most recent call last):
  File "dis_receiver.py", line 40, in <module>
    recv()
  File "dis_receiver.py", line 27, in recv
    data = udpSocket.recv(1024) # buffer size in bytes
socket.timeout: timed out

I don't really understand why this is happening given that I have changed absolutely nothing about the documented example process. Any idea why this would be happening?

Indentation Errors

Hi, I am having trouble running the installation due to indentation errors with the class comments in pythonDis.py. Am I missing a step?

Thanks,
Zach

Allow for multiple receivers on same UDP address/port

Please do something like:

udpSocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

in examples/dis_receiver.py

to allow for multiple receiver's on same host/port.

I don't know if socket.SO_REUSEPORT is an option or not. You may choose to use that instead.

Enjoy getting multicasting working!

signed bytes in signal pdu

I had issues properly reading data from a signal pdu, and tracked it down to code in the SignalPDu and VariableDatum classes.
Specifically, the write_byte method defaults to a signed byte. I was able to successfully use the library after changing instances of "write_byte" to "write_unsigned_byte" and "read_byte" to "read_byte_unsinged".

Specifically on lines:
3605,3609,3618,3623,7144,7160

I also modified line 7141 to "write_unsigned_short" and line 7157 to "read_unsigned_short"
The unsigned shorts were specifically required to get the proper value for larger data lengths.

I suspect all bytes should be unsigned, but have only tested those required for the signal pud.

Boundary padding for records and PDUs

This is a placeholder issue for work relating to boundary padding.

Classes requiring boundary padding

To date, from a quick search in the codebase, the following classes require padding to bit boundaries (Note: not a complete list):

  • IFFData
  • GridAxisDescriptorVariable
  • FundamentalOperationalData
  • Environment
  • IntercomSignalPdu
  • SignalPdu
  • MinefieldResponseNackPdu
  • VariableDatum
  • RecordSpecificationElement

There is some code in VariableDatum for doing this. Ideally the process for doing so should be standardised across all of the above classes. Some helper functions would also help in this area.

Issues affected

This might potentially resolve #12 (since DataPdu composes VariableDatum)

null() call not implemented?

Hi,

Noticed in the code that the null() call doesn't seem to be implemented anywhere. It looks like it should return an instance of some kind of entity class? Maybe a RecordSpecificationElement from poking through the code?

I'm specifically seeing this when parsing an EntityStatePdu packet that apparently has some variable parameters, hitting this block in EntityStatePdu.parse(...):
for idx in range(0, self.numberOfVariableParameters):
element = null()
element.parse(inputStream)
self.variableParameters.append(element)

Is this intentional -- are we supposed to somehow provide a default implementation of null or is this a missing function?

I can get around this by commenting out the lines, which works fine for me as I don't need the variable parameters for what I'm doing. Thought I'd like you know someone out there ran into it.

Thanks!

  • Josh.

Something seems to be very off in the way the data is packed up

I feel like I may be missing something here. I'm springboarding off the example sender like:

    pdu = EntityStatePdu()
    pdu.length = 144 #gotta figure this shit out
    pdu.exerciseID = 250
    pdu.entityID.entityID = 42
    pdu.entityID.siteID = 1
    pdu.entityID.applicationID = 11
    pdu.marking.setString('Igor3d')
    pdu.entityType.domain = 2
    pdu.entityType.country = 255
    pdu.entityType.entityKind = 1

    pdu.forceId = 1

    myLocation = [-5.482955764588357,   # longitude
                    35.198894404096315, # latitude
                    10000,               # altitude
                    0,               # roll
                    0,               # pitch
                    0                # yaw
                     ]
    pdu.entityLocation.x = myLocation[0]
    pdu.entityLocation.y = myLocation[1]
    pdu.entityLocation.z = myLocation[2]
    pdu.entityOrientation.psi = myLocation[3]
    pdu.entityOrientation.theta = myLocation[4]
    pdu.entityOrientation.phi = myLocation[5]
    
    memoryStream = BytesIO()
    outputStream = DataOutputStream(memoryStream)
    pdu.serialize(outputStream)
    data = memoryStream.getvalue()

    while True:
        udpSocket.sendto(data, (DESTINATION_ADDRESS, UDP_PORT))
        pp.pprint(vars(pdu))
        pp.pprint(vars(pdu.entityID))
        pp.pprint(vars(pdu.entityType))
        pp.pprint(vars(pdu.entityLocation))
        print("Sent {}. {} bytes to {}:{}".format(pdu.__class__.__name__, len(data), DESTINATION_ADDRESS, UDP_PORT))
        time.sleep(5)

Then, when I send the data it is printed as below:

{   'alternativeEntityType': <opendis.dis7.EntityType object at 0x7f0a18fb81c0>,
    'capabilities': 0,
    'deadReckoningParameters': <opendis.dis7.DeadReckoningParameters object at 0x7f0a18fb8bb0>,
    'entityAppearance': 0,
    'entityID': <opendis.dis7.EntityID object at 0x7f0a18fb83d0>,
    'entityLinearVelocity': <opendis.dis7.Vector3Float object at 0x7f0a18fb85e0>,
    'entityLocation': <opendis.dis7.Vector3Double object at 0x7f0a18fb86a0>,
    'entityOrientation': <opendis.dis7.EulerAngles object at 0x7f0a18fb8ca0>,
    'entityType': <opendis.dis7.EntityType object at 0x7f0a18fb8cd0>,
    'exerciseID': 250,
    'forceId': 1,
    'length': 144,
    'marking': <opendis.dis7.EntityMarking object at 0x7f0a1869f4c0>,
    'numberOfVariableParameters': 0,
    'padding': 0,
    'pduStatus': 0,
    'pduType': 1,
    'protocolFamily': 1,
    'protocolVersion': 7,
    'timestamp': 0,
    'variableParameters': []}
{'applicationID': 11, 'entityID': 42, 'siteID': 1}
{   'category': 0,
    'country': 255,
    'domain': 2,
    'entityKind': 1,
    'extra': 0,
    'specific': 0,
    'subcategory': 0}
{'x': -5.482955764588357, 'y': 35.198894404096315, 'z': 10000}

Looks great so far. HOWEVER, when I check the packet in Wireshark I get:

"dis": {
          "Header": {
            "dis.proto_ver": "7",
            "dis.exer_id": "250",
            "dis.pdu_type": "1",
            "dis.proto_fam": "1",
            "dis.timestamp": "0.000000000",
            "dis.pdu_length": "144",
            "dis.pdu_status": "0x00000000",
            "dis.pdu_status_tree": {
              "dis.pdustatus.cei": "0x00000000",
              "dis.pdustatus.lvc": "0x00000000",
              "dis.pdustatus.tei": "0x00000000"
            },
            "dis.padding": "00"
          },
          "Entity State PDU": {
            "Entity ID": {
              "dis.entity_id_site": "1",
              "dis.entity_id_application": "11",
              "dis.entity_id_entity": "42"
            },
            "dis.force_id": "1",
            "dis.num_articulation_params": "0",
            "Entity Type, (0:0:0:0:144:1:2) ": {
              "dis.entityKind": "0",
              "dis.entityDomain": "0",
              "dis.country": "0",
              "dis.category": "0",
              "dis.subcategory": "144",
              "dis.specific": "1",
              "dis.extra": "2"
            },
            "Alternative Entity Type, (0:255:0:0:0:0:0) ": {
              "dis.entityKind": "0",
              "dis.entityDomain": "255",
              "dis.country": "0",
              "dis.category": "0",
              "dis.subcategory": "0",
              "dis.specific": "0",
              "dis.extra": "0"
            },
            "Entity Linear Velocity": {
              "dis.entity_linear_velocity.x": "0",
              "dis.entity_linear_velocity.y": "0",
              "dis.entity_linear_velocity.z": "0"
            },
            "Entity Location": {
              "dis.entity_location.x": "2.42946900029516e-319",
              "dis.entity_location.y": "-3.23371005475282e+224",
              "dis.entity_location.z": "-4.9118429119158e-186"
            },
            "Entity Orientation": {
              "dis.entity_orientation.psi": "-3.85186e-34",
              "dis.entity_orientation.theta": "0",
              "dis.entity_orientation.phi": "0"
            },
            "dis.appearance": "0x00000000",
            "Dead Reckoning Parameters": {
              "dis.entity_marking_character_set": "0",
              "dis.dead_reckoning_other_parameters": "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00",
              "Entity Linear Acceleration": {
                "dis.entity_linear_acceleration.x": "0",
                "dis.entity_linear_acceleration.y": "0",
                "dis.entity_linear_acceleration.z": "0"
              },
              "Entity Angular Velocity": {
                "dis.entity_angular_velocity.x": "0",
                "dis.entity_angular_velocity.y": "0",
                "dis.entity_angular_velocity.z": "0"
              }
            },
            "Entity Marking": {
              "dis.entity_marking_character_set": "0"
            },
            "dis.capabilities": "1677721600"

As you can see, the entityType and location info is ignored or changed.
Any help in understanding what I'm doing wrong would be greatly appreciated.
Thank you

When serializing, length field is always zero

In the dis_sender.py, the emitted ESPDU has its length field set to zero.

The code in that example doesn't manipulate the length field.

This matters if you're using, say, open-dis java's PduFactory#getPdusFromBundle()`, which relies on this field's value.

VariableDatum object cannot hold negative signed integers

VariableDatum objects throw struct.error when you try to store negative signed integers (e.g. -1=b'\xff') in the variableData field, then serialize.

MVP

This is the minimum viable product to reproduce the error

from opendis.dis7 import VariableDatum
from opendis.DataOutputStream import DataOutputStream
from io import BytesIO
import struct

variable_datum = VariableDatum()
data = list((b'\x00'*4)+struct.pack('>i',-1))
variable_datum.variableData = data
variable_datum.variableDatumLength = len(data)*8
memoryStream = BytesIO()
outputStream = DataOutputStream(memoryStream)
variable_datum.serialize(outputStream)
print(memoryStream.getvalue())

Expected Behavior

I expect variable_datum to serialize without an error, and for the final print to display the serialized object (should be b'\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\xff\xff\xff\xff')

Actual Behavior

The script throws a struct.error when variable_datum tries to serialize.

Full error

This is the full error that is thrown when variable_datum tries to serialize.

Traceback (most recent call last):
  File "test.py", line 12, in <module>
    variable_datum.serialize(outputStream)
  File "C:\Users\e389403\AppData\Local\Programs\Python\Python37-32\lib\site-packages\opendis\dis7.py", line 3586, in serialize
    outputStream.write_byte(self.variableData[x])
  File "C:\Users\e389403\AppData\Local\Programs\Python\Python37-32\lib\site-packages\opendis\DataOutputStream.py", line 17, in write_byte
    self.stream.write(struct.pack('b', val))
struct.error: byte format requires -128 <= number <= 127

Possible solutions

From what I can gather, when serialize is called:

  • serialize() is called
  • for each byte in the variableData bytes object, it calls outputStream.write_byte())
    This means that when it reaches b'\xff's, it tries to write 255 as a signed byte to outputStream.
  • thus it tries to call struct.pack('b', 255) which results in an error, rightly so because it's out of range(0, 256).

When I changed dis7.py line 3586 to outputStream.write_unsigned_byte(self.variableData[x]), then I got the expected behavior.

Notes

Signed integers actually parse without error. This makes sense, since inputStream.read_byte() is used to parse the bytes when forming the variableData list.

from opendis.dis7 import VariableDatum
from opendis.DataInputStream import DataInputStream
from io import BytesIO

memoryStream = BytesIO(b'\x00\x00\x00\x00\x00\x00\x00@\x00\x00\x00\x00\xff\xff\xff\xff')
inputStream = DataInputStream(memoryStream)
new_variable_datum = VariableDatum()
new_variable_datum.parse(inputStream)
print(new_variable_datum.variableData) # [0, 0, 0, 0, -1, -1, -1, -1]

Example sender isn't looping as suggested in README

The README.md suggests that after running the dis_sender.py the user should press Ctrl + \ to stop the process. But when I run the script it sends a single Entity State PDU and stops. The code in the dis_sender.py supports this and doesn't contain a loop.

variableParameters

Trying to insert variableParameters into my DIS packets for VBS3

Ive managed to create packets and have the Entity display over a network into VBS, this works very well, however Im now trying to get articulation working via variableParameters.

no matter what I set nothing shows up in wireshark.

Has anyone managed to get this to work yet?

many thanks

Spriggsy

Malformed packet data

Outgoing Entity PDU packets are showing up as malformed in wireshark. To test I captured a known good Entity packet from VT-Mak and saved it as a binary file. Then I simply load it, de-serialize, serialize, and rebroadcast.

Config options mapped to symbolic names (6.1.8)

IEEE1278.1-2012 has a section (6.1.8) on fixed and variable parameters defined prior to an exercise in an exercise agreement.

Some of these parameters affect the packing, transmission, and receipt of PDUs, e.g. tolerances of ESPDUs, MAX_PDU_SIZE_BITS/OCTETS.

I'm putting a placeholder issue here for when we eventually get round to setting up config, as a reminder to refer to this section for option names.

Issue with dis_recieve.py createPdu()

Created UDP socket 62040
Traceback (most recent call last):
File ".\dis_receiver.py", line 41, in
recv()
File ".\dis_receiver.py", line 30, in recv
aPdu = createPdu(data)
File "C:\Users\berliaj1\Anaconda3\lib\site-packages\opendis\PduFactory.py", line 92, in createPdu
return getPdu(inputStream)
File "C:\Users\berliaj1\Anaconda3\lib\site-packages\opendis\PduFactory.py", line 75, in getPdu
pdu.parse(inputStream)
File "C:\Users\berliaj1\Anaconda3\lib\site-packages\opendis\dis7.py", line 5128, in parse
self.marking.parse(inputStream)
File "C:\Users\berliaj1\Anaconda3\lib\site-packages\opendis\dis7.py", line 1356, in parse
val = inputStream.read_byte()
File "C:\Users\berliaj1\Anaconda3\lib\site-packages\opendis\DataInputStream.py", line 17, in read_byte
return struct.unpack('b', self.stream.read(1))[0]
struct.error: unpack requires a buffer of 1 bytes

Feature request: Local to Euler angles conversion

I previously was using the java variant of opendis, and it came with a helper function for converting heading/roll/pitch to euler angles for transmission.

I'm using the python version now, and I wish that it had a helper function.

Inconsistent naming for attributes representing a count

numberOf* vs *Count

In the PDF specification, the two terms are used interchangeably. However, when programming, it is helpful to establish a consistent naming convention so that programmers do not need to keep looking up the attribute names.

There are currently two ways of naming values that represent the count/number of records or values:

outputStream.write_unsigned_int(self.numberOfFixedDatumIDs)
outputStream.write_unsigned_int(self.numberOfVariableDatumIDs)

vs

self.falseTargetCount = falseTargetCount

Pros and cons

Pros of numberOf* naming

  • ???

Pros of *Count naming

  • convenient visual alignment (fixedDatumIDs and fixedDatumIDCount will left-align for easier visual identification when browsing code)
  • shorter attribute names

This is admittedly a minor issue and might not affect many users, though it's clear where my biases lie. Currently it's a minor speedbump for my work on the repo, and I can wait for a resolution on (a) whether consistent naming would be beneficial, (b) which naming convention to go with.

null() Function Call?

Python doesn't recognize the null() function call.

Line 129 of dis7.py is 1st example.

        for idx in range(0, self.recordLength):
            element = null()
            element.parse(inputStream)
            self.iffData.append(element)

Is this supposed to be None?

EmissionSystemBeamRecord.serialize incorrectly contains outputStream read calls instead of write

def serialize(self, outputStream):
outputStream.read_unsigned_byte(self.beamDataLength);
outputStream.read_unsigned_byte(self.beamIDNumber);
outputStream.read_unsigned_short(self.beamParameterIndex);
self.fundamentalParameterData.serialize(outputStream);
outputStream.read_unsigned_byte(self.beamFunction);
outputStream.read_unsigned_byte(self.numberOfTargetsInTrackJam);
outputStream.read_unsigned_byte(self.highDensityTrackJam);
outputStream.read_unsigned_byte(0); # 8 bit padding
outputStream.read_unsigned_int(self.jammingModeSequence);

EmissionSystemBeamRecord's serialize function implementation is incorrectly attempting to call outputStream.read_unsigned_byte and outputStream.read_unsigned_short, which do not exist, and should be writes.

The read calls need to be replaced with the correct write calls: outputStream.write_unsigned_byte and outputStream.write_unsigned_short

Confusing naming for identifiers

Identifier naming

Identifier classes

There is currently an EntityID class:

class EntityID( object ):
"""more laconically named EntityIdentifier"""
def __init__(self,
siteID=0,
applicationID=0,
entityID=0):
""" Initializer for EntityID"""
self.siteID = siteID
""" Site ID"""
self.applicationID = applicationID
""" application number ID"""
self.entityID = entityID
""" Entity number ID"""

But there is also an EntityIdentifier class:

class EntityIdentifier( object ):
"""Entity Identifier. Unique ID for entities in the world. Consists of an simulation address and a entity number. Section 6.2.28."""
def __init__(self,
simulationAddress=None,
entityNumber=0):
""" Initializer for EntityIdentifier"""
self.simulationAddress = simulationAddress or SimulationAddress()
""" Site and application IDs"""
self.entityNumber = entityNumber
""" Entity number"""

There are also other Identifier classes:

  • IntercomIdentifier
  • EventIdentifier
  • ObjectIdentifier
  • SystemIdentifier
  • AggregateIdentifier
  • RadioIdentifier
  • UnattachedIdentifier
  • EventIdentifierLiveEntity
  • LiveEntityIdentifier
  • MineEntityIdentifier
  • SimulationIdentifier
  • MinefieldIdentifier

EntityID seems to stick out to me here as being named differently from the rest, yet it is used throughout dis7.py.

Identifier reference

Section 4.2.5.2 refers to object identifiers as "the designators assigned to uniquely identify objects such as entities, aggregates, minefields, environmental processes, groups of entities and points, and linear and areal objects."

image

Section 4.2.5.3 refers to other identifiers as being "used to designate other data items that are not objects."

image

Proposal

For closer coherence with the spec and documentation, and to lay some groundwork for future features, I propose the following changes.

Rename EntityID

To reduce dissonance between the codebase and the documentation, I propose to use EntityIdentifier as the standard identifier class for entities. All object identifiers should also have their init parameters take a siteNo, appNo, and refNo (instead of a SimulationAddress and a refNo).

Make ObjectIdentifier a superclass

To make instance/subclass checking (using isinstance() and issubclass()) possible, I propose to have the following classes inherit from an ObjectIdentifier superclass:

  • EntityIdentifier
  • AggregateIdentifier
  • EnvObjectIdentifier (renamed from ObjectIdentifier above; shared by PointObjectIdentifier, Linear Object Identifier, and Areal Object Identifier)
  • LiveEntityIdentifier
  • GroupIdentifier
  • GroupEntityIdentifier
  • MinefieldIdentifier
  • MineEntityIdentifier
  • EnvProcessIdentifier (or spelled out in full)

This would be useful for future work, since ObjectIdentifiers are supposed to be unique even across object types. It would enable tracking of instantiated ObjectIdentifier subclasses through the superclass, if such a feature is desired.

Other Identifiers

These identifiers, due to their varied nature and interface, should remain independent classes that do not subclass ObjectIdentifier. They will nonetheless still retain the -Identifier suffix.

Namespace identifier classes separately

Many attributes in dis7.py are named/suffixed as ID, yet do not hold an instance of one of the above classes (e.g. actionID in ActionRequestPdu is an enum struct). Separating the object identifiers (4.2.5.2) and other identifiers (4.2.5.3) more distinctly from the other classes will make reference lookup easier and help with disambiguation.

I suggest moving them to an identifier.py file, since none of the values rely on other classes in dis7.py, aside from SystemIdentifier requiring an instance of ChangeOptions which no other class relies on. The classes can be explicitly imported into dis7.py by name, so no other changes to dis7.py are needed.

I'm willing to make a pull request incorporating these changes.

VariableDatum object does not serialize padding

The variable datum object only serialises the actual data, but recieved pdus will be parsed as though padding has been sent as well.
This results in the variable datum object ignoring several of the bits it recieves, and attempting to read more from
the input stream than has been sent.

Issue in code:

(code from line 3579 of dis7.py, my comments start with #########)

def serialize(self, outputStream):
        """serialize the class """
        outputStream.write_unsigned_int(self.variableDatumID);
        outputStream.write_unsigned_int(self.variableDatumLength);
        for x in range(self.variableDatumLength // 8): # length is in bits
            outputStream.write_byte(self.variableData[x])
													
		######### no padding is sent, only data from variableData within the size of variableDatumLength field


 def parse(self, inputStream):
        """"Parse a message. This may recursively call embedded objects."""
        self.variableDatumID = inputStream.read_unsigned_int();
        self.variableDatumLength = inputStream.read_unsigned_int();
        for x in range(self.variableDatumLength // 8): # length is in bits
            self.variableData.append(inputStream.read_byte());

              ######## the parse function expects padding
    # Skip over padding
    # "This field shall be padded at the end to make the length a multiple of 64-bits."
    for x in range(self.datumPaddingSizeInBits() // 8):
        inputStream.read_byte()

Expected behaviour:

The serialise function should send a number of zeros corresponding to the padding size of the datum.

Fix:

This isssue could be fixed by adding the following code to the end of the serialize function:

for x in range(self.datumPaddingSizeInBits() // 8):
            inputStream.write_byte(0)

EntityMarking only serializes 11 of 12 required bytes

According to the DIS Data Dictionary on Entity State PDUs, the Entity Marking Record should be 12 bytes (96 bits) long.

In dis7.py line 1351, in the serialize method of the EntityMarking class, the for loop only loops through 11 list elements:

def serialize(self, outputStream):
        """serialize the class """
        outputStream.write_unsigned_byte(self.characterSet);
        for idx in range(0, 11):
            outputStream.write_byte( self.characters[ idx ] );

range(0, 11) only lets the maximum value for idx be 10, which means it only loops through 11 bytes, not 12 (which is the required amount by the DIS standard). The same problem exists in the parse method of the EntityMarking class, where it only reads in 11 bytes. This causes a loss of information when receiving ESPDUs.

Furthermore, in the EntityMarking class, the initial value for the self.characters list only contains 11 elements.

ElectronicEmmisionsPdu does not handle beams correctly

For each EmmisionSystemRecord in the ElectronicEmmisionsPdu the beam handling assumes 1 beam always, so if there are no beams you will get a failed parse and if there are multiple beams you will only get the first

I will submit a pull request with a fix when I have it.

Typographical Error in ReceiverPdu

In 'dis7.py' there is a minor typo on lines 6914, 6928 and 6939 relating to the 'receivedPower', it was accidentally written as 'receivedPoser'.

NameError: name 'getPdu' is not defined

This commit broke the parsing of the CommentPdu. Here is the trace:

...
 File "/usr/local/lib/python3.6/dist-packages/distributed_interactive_simulation-1.0-py3.6.egg/distributed_interactive_simulation/PduFactory.py", line 91, in createPdu
    return getPdu(inputStream)
  File "/usr/local/lib/python3.6/dist-packages/distributed_interactive_simulation-1.0-py3.6.egg/distributed_interactive_simulation/PduFactory.py", line 74, in getPdu
    pdu.parse(inputStream)
  File "/usr/local/lib/python3.6/dist-packages/distributed_interactive_simulation-1.0-py3.6.egg/distributed_interactive_simulation/dis7.py", line 6446, in parse
    self.variableDatums.append(getPdu(inputStream))
NameError: name 'getPdu' is not defined

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.