Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
f0f86f0
[feat] add read_bytes() and write_bytes() methods
ngjunsiang May 18, 2024
738382d
[refactor] add specific non-octet-size type aliases for bitfields
ngjunsiang May 18, 2024
c0fb495
[feat] bitfield factory function, NetId and SpreadSpectrum record cla…
ngjunsiang May 18, 2024
346b8bf
[docs] TransmitterPdu comments cleanup
ngjunsiang May 18, 2024
1b7f071
[refactor] Add default values to allow init without initial values
ngjunsiang May 18, 2024
bff4aa3
[refactor] Use SpreadSpectrum in ModulationType
ngjunsiang May 18, 2024
a86ae5c
[fix] bugfixes
ngjunsiang May 18, 2024
3b5cf7a
Merge branch 'open-dis:master' into feat-bitfield
ngjunsiang May 18, 2024
ba89412
[cleanup] minor edits
ngjunsiang May 18, 2024
8a1ea52
Merge branch 'master' into feat-bitfield
ngjunsiang May 18, 2024
1aaaa87
[fix] Bitfield packs into correct number of bytes
ngjunsiang May 18, 2024
9acd3b8
[fix] Use SpreadSpectrum to parse and serialize stream
ngjunsiang May 18, 2024
d9e211c
[fix] SignalPdu correctly parses data samples
ngjunsiang May 19, 2024
d06a00b
fix regression of parsing dataLenght in SignalPdu in 98b2834
skrsta Jul 6, 2024
546be77
ci: publishes library to local registry
Jul 28, 2025
08ffdb8
feat: allow a newer version of numpy
Jul 28, 2025
8949fdc
feat: alpha releases now indicate accel opendis releases
Jul 28, 2025
57abd22
ci: added cz autobump
Jul 28, 2025
c2b9b10
ci: fixed issue with entrypoint
Jul 28, 2025
f6ea817
ci: fixed entrypoint issue
Jul 28, 2025
b6457b1
build: adding docker support for builds
Jul 28, 2025
6b88680
ci: fix major version error with cz bump
Jul 28, 2025
e7d16bb
build: made version consistent with commitizen naming
Jul 28, 2025
7ee5813
bump: 1.1.0a0 → 1.1.0a1
Jul 28, 2025
13b61d5
docs: add more info to changelog about changes
Jul 28, 2025
f2e96b6
bump: 1.1.0a1 → 1.1.0a2
Jul 28, 2025
483cf29
test: adds pytest and coverage support
Jul 29, 2025
041a4f9
bump: 1.1.0a2 → 1.1.0a3
Jul 29, 2025
402d949
fix: fixes broken examples (dis_receiver and dis_sender), corrects fu…
Jul 29, 2025
a63d021
bump: 1.1.0a3 → 1.1.0a4
Jul 29, 2025
15bac95
ci: add github ci and remove gitlab ci (#2)
btweinstein Jul 30, 2025
15c87e1
chore: removed other unecessary gitlab files
Jul 30, 2025
c24e39a
chore: removed uneeded file
Jul 30, 2025
7174fdc
added beam status field to EmissionSystemBeamRecord
Aug 27, 2025
0b68e3e
AggregateStatePDU ground work
robomarvin1501 Sep 11, 2025
54e4fda
Serialisation should now be correctly handled, with regards to the
robomarvin1501 Sep 13, 2025
50033ea
Parsing is correctly handled, but need to switch to @property for the…
robomarvin1501 Sep 13, 2025
e956906
Handling the number of element x properties as @property, instead of …
robomarvin1501 Sep 13, 2025
78f28bd
Marking AggregateStatePDU as complete, as verified in Wireshark
robomarvin1501 Sep 14, 2025
3fc0061
fix serialization issues
Sep 16, 2025
6812943
fix serialization issues
Sep 16, 2025
73917e9
fix jamming mode issue
Sep 16, 2025
5d3e141
[docs] TransmitterPdu comments cleanup
ngjunsiang May 18, 2024
396abb2
[fix] SignalPdu correctly parses data samples
ngjunsiang May 19, 2024
ec0617d
Merge branch 'master' into feat-bitfield
ngjunsiang Sep 18, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions opendis/DataInputStream.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,6 @@ def read_int(self) -> int32:

def read_unsigned_int(self) -> uint32:
return struct.unpack('>I', self.stream.read(4))[0]

def read_bytes(self, n: int) -> bytes:
return self.stream.read(n)
3 changes: 3 additions & 0 deletions opendis/DataOutputStream.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,3 +48,6 @@ def write_int(self, val: int) -> None:
def write_unsigned_int(self, val: int) -> None:
self.stream.write(struct.pack('>I', val))

def write_bytes(self, val: bytes) -> None:
self.stream.write(val)

21 changes: 9 additions & 12 deletions opendis/dis7.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@
enum8,
enum16,
enum32,
int8,
int16,
int32,
uint8,
uint16,
Expand All @@ -19,6 +17,7 @@
struct16,
struct32,
)
from .record import SpreadSpectrum


class DataQueryDatumSpecification:
Expand Down Expand Up @@ -2025,11 +2024,11 @@ class ModulationType:
"""

def __init__(self,
spreadSpectrum: struct16 = 0, # See RPR Enumerations
spreadSpectrum: SpreadSpectrum | None = None, # See RPR Enumerations
majorModulation: enum16 = 0, # [UID 155]
detail: enum16 =0, # [UID 156-162]
radioSystem: enum16 =0): # [UID 163]
self.spreadSpectrum = spreadSpectrum
detail: enum16 = 0, # [UID 156-162]
radioSystem: enum16 = 0): # [UID 163]
self.spreadSpectrum = spreadSpectrum or SpreadSpectrum()
"""This field shall indicate the spread spectrum technique or combination of spread spectrum techniques in use. Bit field. 0=freq hopping, 1=psuedo noise, time hopping=2, reamining bits unused"""
self.majorModulation = majorModulation
"""the major classification of the modulation type."""
Expand All @@ -2040,14 +2039,14 @@ def __init__(self,

def serialize(self, outputStream):
"""serialize the class"""
outputStream.write_unsigned_short(self.spreadSpectrum)
self.spreadSpectrum.serialize(outputStream)
outputStream.write_unsigned_short(self.majorModulation)
outputStream.write_unsigned_short(self.detail)
outputStream.write_unsigned_short(self.radioSystem)

def parse(self, inputStream):
"""Parse a message. This may recursively call embedded objects."""
self.spreadSpectrum = inputStream.read_unsigned_short()
self.spreadSpectrum.parse(inputStream)
self.majorModulation = inputStream.read_unsigned_short()
self.detail = inputStream.read_unsigned_short()
self.radioSystem = inputStream.read_unsigned_short()
Expand Down Expand Up @@ -5477,12 +5476,13 @@ def __init__(self,
antennaPatternList=None):
super(TransmitterPdu, self).__init__()
self.radioReferenceID = radioReferenceID or EntityID()
"""ID of the entitythat is the source of the communication"""
"""ID of the entity that is the source of the communication"""
self.radioNumber = radioNumber
"""particular radio within an entity"""
self.radioEntityType = radioEntityType or EntityType() # TODO: validation
self.transmitState = transmitState
self.inputSource = inputSource
self.variableTransmitterParameterCount = variableTransmitterParameterCount
self.antennaLocation = antennaLocation or Vector3Double()
self.relativeAntennaLocation = relativeAntennaLocation or Vector3Float(
)
Expand All @@ -5491,7 +5491,6 @@ def __init__(self,
self.frequency = frequency
self.transmitFrequencyBandwidth = transmitFrequencyBandwidth
self.power = power
"""transmission power"""
self.modulationType = modulationType or ModulationType()
self.cryptoSystem = cryptoSystem
self.cryptoKeyId = cryptoKeyId
Expand All @@ -5500,9 +5499,7 @@ def __init__(self,
self.padding2 = 0
self.padding3 = 0
self.modulationParametersList = modulationParametersList or []
"""variable length list of modulation parameters"""
self.antennaPatternList = antennaPatternList or []
"""variable length list of antenna pattern records"""
# TODO: zero or more Variable Transmitter Parameters records (see 6.2.95)

@property
Expand Down
143 changes: 143 additions & 0 deletions opendis/record.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
from collections.abc import Sequence
from ctypes import c_uint8, c_uint16, BigEndianStructure

from .types import (
bf_enum,
bf_uint,
)
from .DataInputStream import DataInputStream
from .DataOutputStream import DataOutputStream


def bitfield(
name: str,
bytesize: int,
fields: Sequence[tuple],
):
"""Factory function for bitfield structs, which are subclasses of
ctypes.Structure.
These are used in records that require them to unpack non-octet-sized fields.

Arguments
---------
name: str
The name of the bitfield struct.
bytesize: int
The number of bytes required by the bitfield, including padding.
fields: Sequence[tuple[str, ctypes._CData] | tuple[str, ctypes._CData, int]]
A sequence of field descriptions. See ctypes.Structure documentation for details.
"""
assert bytesize > 0, "Cannot create bitfield with zero bytes"

class Bitfield(BigEndianStructure):
_fields_ = fields

@staticmethod
def marshalledSize() -> int:
return bytesize

def serialize(self, outputStream: DataOutputStream) -> None:
outputStream.write_bytes(bytes(self))

@classmethod
def parse(cls, inputStream: DataInputStream) -> "Bitfield":
return cls.from_buffer_copy(inputStream.read_bytes(bytesize))
Bitfield.__name__ = name
return Bitfield


class NetId:
"""Annex C, Table C.5

Represents an Operational Net in the format of NXX.XYY, where:
N = Mode
XXX = Net Number
YY = Frequency Table
"""
_struct = bitfield("NetId", 2, [
("netNumber", c_uint16, 10),
("frequencyTable", c_uint8, 2),
("mode", c_uint8, 2),
("padding", c_uint8, 2)
])

def __init__(self,
netNumber: bf_uint = 0,
frequencyTable: bf_enum = 0, # [UID 299]
mode: bf_enum = 0, # [UID 298]
padding: bf_uint = 0):
# Net number ranging from 0 to 999 decimal
self.netNumber = netNumber
self.frequencyTable = frequencyTable
self.mode = mode
self.padding = padding

def marshalledSize(self) -> int:
return self._struct.marshalledSize()

def serialize(self, outputStream: DataOutputStream) -> None:
self._struct(
self.netNumber,
self.frequencyTable,
self.mode,
self.padding
).serialize(outputStream)

def parse(self, inputStream: DataInputStream) -> None:
record_bitfield = self._struct.parse(inputStream)
self.netNumber = record_bitfield.netNumber
self.frequencyTable = record_bitfield.frequencyTable
self.mode = record_bitfield.mode
self.padding = record_bitfield.padding


class SpreadSpectrum:
"""6.2.59 Modulation Type Record, Table 90

Modulation used for radio transmission is characterized in a generic
fashion by the Spread Spectrum, Major Modulation, and Detail fields.

Each independent type of spread spectrum technique shall be represented by
a single element of this array.
If a particular spread spectrum technique is in use, the corresponding array
element shall be set to one; otherwise it shall be set to zero.
All unused array elements shall be set to zero.

In Python, the presence or absence of each technique is indicated by a bool.
"""
_struct = bitfield("SpreadSpectrum", 2, [
("frequencyHopping", c_uint8, 1),
("pseudoNoise", c_uint8, 1),
("timeHopping", c_uint8, 1),
("padding", c_uint16, 13)
])

def __init__(self,
frequencyHopping: bool = False,
pseudoNoise: bool = False,
timeHopping: bool = False,
padding: bf_uint = 0):
self.frequencyHopping = frequencyHopping
self.pseudoNoise = pseudoNoise
self.timeHopping = timeHopping
self.padding = padding

def marshalledSize(self) -> int:
return self._struct.marshalledSize()

def serialize(self, outputStream: DataOutputStream) -> None:
# Bitfield expects int input
self._struct(
int(self.frequencyHopping),
int(self.pseudoNoise),
int(self.timeHopping),
self.padding
).serialize(outputStream)

def parse(self, inputStream: DataInputStream) -> None:
# Pass bool to __init__ instead of int
record_bitfield = self._struct.parse(inputStream)
self.frequencyHopping = bool(record_bitfield.frequencyHopping)
self.pseudoNoise = bool(record_bitfield.pseudoNoise)
self.timeHopping = bool(record_bitfield.timeHopping)

5 changes: 5 additions & 0 deletions opendis/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,8 @@
struct32 = int
char8 = str
char16 = str

# Non-octet-size types for bitfields
bf_enum = int
bf_int = int
bf_uint = int
Loading