108 lines
2.7 KiB
Python
108 lines
2.7 KiB
Python
import struct
|
|
import pytest
|
|
|
|
from enum import Enum
|
|
|
|
from pybusmonitor1553.lib1553.fields import Field, BitField, EnumField, ScaledField, ASCIIField
|
|
from pybusmonitor1553.lib1553.message_base import MessageBase
|
|
from pybusmonitor1553.lib1553.messages.msg_a3 import MsgA3
|
|
from pybusmonitor1553.lib1553.messages.msg_a5 import MsgA5
|
|
|
|
|
|
def test_descriptor_returns_self_on_class_access():
|
|
class M(MessageBase):
|
|
bf = BitField(word_index=0, start_bit=0, width=1)
|
|
|
|
# Accessing via class should return the descriptor itself
|
|
assert isinstance(M.bf, BitField)
|
|
|
|
|
|
def test_enumfield_auto_width_and_fallback():
|
|
class E(Enum):
|
|
A = 0
|
|
B = 1
|
|
C = 3
|
|
|
|
class M(MessageBase):
|
|
ef = EnumField(word_index=0, start_bit=0, enum_cls=E) # width auto
|
|
|
|
# Width auto-calculated to fit max value (3 -> 2 bits)
|
|
assert M.ef.width == 2
|
|
|
|
m = M()
|
|
# Set raw value directly to an undefined value (e.g., 2)
|
|
m.data[0] = 2 << (16 - (0 + M.ef.width))
|
|
# Should return raw int because 2 not in Enum
|
|
assert m.ef == 2
|
|
|
|
|
|
def test_asciifield_nonprintable_and_validation():
|
|
class M(MessageBase):
|
|
a = ASCIIField(word_index=0)
|
|
|
|
m = M()
|
|
# write a raw word with non-printable bytes 0x00 0x01
|
|
m._data[0] = (0 << 8) | 1
|
|
assert m.a == '??'
|
|
|
|
with pytest.raises(ValueError):
|
|
m.a = 'X' # too short
|
|
|
|
|
|
def test_message_base_pack_unpack_and_clamp():
|
|
class M(MessageBase):
|
|
pass
|
|
|
|
m = M()
|
|
# set some sample words
|
|
for i in range(32):
|
|
m._data[i] = i
|
|
|
|
packed = m.pack()
|
|
assert len(packed) == 64
|
|
|
|
# create raw with more than 32 words (e.g., 40 words)
|
|
extra = struct.pack('>40H', *list(range(40)))
|
|
m2 = M()
|
|
m2.unpack(extra)
|
|
# only first 32 should be loaded
|
|
assert m2._data[31] == 31
|
|
|
|
|
|
def test_msg_a3_25bit_signed_and_ascii():
|
|
m = MsgA3()
|
|
|
|
# positive raw
|
|
raw_25 = 0x00ABCDE
|
|
msw = (raw_25 >> 9) & 0xFFFF
|
|
lsw_fragment = raw_25 & 0x1FF
|
|
m._data[2] = msw
|
|
m._data[3] = (lsw_fragment << 7)
|
|
assert isinstance(m.wp1_latitude, float)
|
|
|
|
# negative value: set sign bit of 25-bit value
|
|
neg_raw = (1 << 24) | 12345
|
|
msw = (neg_raw >> 9) & 0xFFFF
|
|
lsw_fragment = neg_raw & 0x1FF
|
|
m._data[4] = msw
|
|
m._data[5] = (lsw_fragment << 7)
|
|
val = m.wp1_longitude
|
|
assert isinstance(val, float)
|
|
|
|
# ASCII fields
|
|
m.hpt_callsign_ab = 'AA'
|
|
assert m.hpt_callsign_ab == 'AA'
|
|
|
|
|
|
def test_msg_a5_32bit_signed_scaled_velocity():
|
|
m = MsgA5()
|
|
# build a negative 32-bit raw value
|
|
raw32 = (1 << 31) | 12345678 # sign bit set
|
|
msw = (raw32 >> 16) & 0xFFFF
|
|
lsw = raw32 & 0xFFFF
|
|
m._data[2] = msw
|
|
m._data[3] = lsw
|
|
|
|
expected = float((raw32 - (1 << 32)) * 3.81470e-6)
|
|
assert pytest.approx(m.velocity_x, rel=1e-9) == expected
|