Skip to content

Commit

Permalink
Merge pull request #104 from CarletonURocketry/coordinate-db
Browse files Browse the repository at this point in the history
Add coordinates data block
  • Loading branch information
linguini1 authored Jun 6, 2024
2 parents 697e813 + eba8438 commit 55ab33a
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 44 deletions.
129 changes: 87 additions & 42 deletions modules/telemetry/v1/data_block.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,11 @@ def parse(block_subtype: DataBlockSubtype, payload: bytes) -> DataBlock:
DataBlockSubtype.ALTITUDE_LAUNCH_LEVEL: AltitudeLaunchLevelDB,
DataBlockSubtype.TEMPERATURE: TemperatureDB,
DataBlockSubtype.PRESSURE: PressureDB,
DataBlockSubtype.HUMIDITY: HumidityDB,
DataBlockSubtype.LIN_ACCEL_REL: RelativeLinearAccelerationDB,
DataBlockSubtype.LIN_ACCEL_ABS: AbsoluteLinearAccelerationDB,
DataBlockSubtype.ANGULAR_VELOCITY: AngularVelocityDB,
DataBlockSubtype.HUMIDITY: HumidityDB,
DataBlockSubtype.COORDINATES: CoordinatesDB,
DataBlockSubtype.VOLTAGE: VoltageDB,
}

Expand Down Expand Up @@ -290,47 +291,6 @@ def __iter__(self):
yield "pressure", {"pascals": self.pressure, "psi": pascals_to_psi(self.pressure)}


class HumidityDB(DataBlock):
"""Represents a humidity data block."""

def __init__(self, mission_time: int, humidity: int) -> None:
"""
Constructs a humidity data block.
Args:
mission_time: The mission time the humidity was measured at in milliseconds since launch.
humidity: The calculated relative humidity in ten thousandths of a percent.
"""
super().__init__(mission_time)
self.humidity: int = humidity

@classmethod
def from_bytes(cls, payload: bytes) -> Self:
"""
Constructs a humidity data block from bytes.
Returns:
A humidity data block.
"""
parts = struct.unpack("<II", payload)
return cls(parts[0], parts[1])

def __len__(self) -> int:
"""
Get the length of a humidity data block in bytes.
Returns:
The length of a humidity data block in bytes, not including the block header.
"""
return 8

def __str__(self):
return f"{self.__class__.__name__} -> time: {self.mission_time} ms, humidity: {round(self.humidity / 100)}%"

def __iter__(self):
yield "mission_time", self.mission_time
yield "percentage", round(self.humidity / 100)


class LinearAccelerationDB(DataBlock):
"""Represents a linear acceleration data block"""

Expand Down Expand Up @@ -439,6 +399,91 @@ def __iter__(self):
yield "angular_velocity", {"x": self.x_axis, "y": self.y_axis, "z": self.z_axis, "magnitude": self.magnitude}


class HumidityDB(DataBlock):
"""Represents a humidity data block."""

def __init__(self, mission_time: int, humidity: int) -> None:
"""
Constructs a humidity data block.
Args:
mission_time: The mission time the humidity was measured at in milliseconds since launch.
humidity: The calculated relative humidity in ten thousandths of a percent.
"""
super().__init__(mission_time)
self.humidity: int = humidity

@classmethod
def from_bytes(cls, payload: bytes) -> Self:
"""
Constructs a humidity data block from bytes.
Returns:
A humidity data block.
"""
parts = struct.unpack("<II", payload)
return cls(parts[0], parts[1])

def __len__(self) -> int:
"""
Get the length of a humidity data block in bytes.
Returns:
The length of a humidity data block in bytes, not including the block header.
"""
return 8

def __str__(self):
return f"{self.__class__.__name__} -> time: {self.mission_time} ms, humidity: {round(self.humidity / 100)}%"

def __iter__(self):
yield "mission_time", self.mission_time
yield "percentage", round(self.humidity / 100)


class CoordinatesDB(DataBlock):
"""Represents a coordinates data block"""

def __init__(self, mission_time: int, latitude: int, longitude: int) -> None:
"""
Constructs a coordinates data block.
Args:
mission_time: The mission time the coordinates were measured in milliseconds since launch.
latitude: The latitude in units of micro-degrees.
longitude: The longitude in units of micro-degrees.
"""
super().__init__(mission_time)
self.latitude: int = latitude
self.longitude: int = longitude

@classmethod
def from_bytes(cls, payload: bytes) -> Self:
"""
Constructs a coordinates data block from bytes.
Returns:
A coordinates data block.
"""
parts = struct.unpack("<Iii", payload)
return cls(parts[0], parts[1], parts[2])

def __len__(self) -> int:
"""
Get the length of a coordinates data block in bytes
Returns:
The length of a coordinates data block in bytes not including the block header.
"""
return 12

def __str__(self):
return f"""{self.__class__.__name__} -> time: {self.mission_time} ms, latitude: {(self.latitude / pow(10, 7))}°
, longitude: {(self.longitude / pow(10, 7))}°"""

def __iter__(self):
yield "mission_time", self.mission_time
yield "latitude", self.latitude
yield "longitude", self.longitude


class VoltageDB(DataBlock):
"""Represents a voltage data block"""

Expand Down
42 changes: 40 additions & 2 deletions tests/parsing/test_block_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
TemperatureDB,
LinearAccelerationDB,
AngularVelocityDB,
HumidityDB,
CoordinatesDB,
VoltageDB,
)

Expand Down Expand Up @@ -60,8 +62,27 @@ def angular_velocity_data_content() -> bytes:


@pytest.fixture
# 9b0d00000200ee0c
# DEBUG:modules.telemetry.telemetry_utils:VoltageDB -> time: 3483 ms, id: 2, voltage: 3310 mV
def humidity_data_content() -> bytes:
"""
Returns a humidity sensor reading with the following attributes
mission time: 4121ms
humidity: 44%
"""
return b"\x19\x10\x00\x00\xfe\x10\x00\x00"


@pytest.fixture
def coordinates_data_content() -> bytes:
"""
Returns a coordinates sensor reading with the following attributes
mission time: 3340ms
latitude: 0
longitude: 0
"""
return b"\x0c\x0d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"


@pytest.fixture
def voltage_data_content() -> bytes:
"""
Returns a voltage sensor reading with the following attributes
Expand Down Expand Up @@ -110,6 +131,23 @@ def test_angular_velocity_data_block(angular_velocity_data_content: bytes) -> No
assert ang_vel.magnitude == 1.29


def test_humidity_data_block(humidity_data_content: bytes) -> None:
"""Test that the humidity data block is parsed correctly."""
hdb = HumidityDB.from_bytes(humidity_data_content)

assert hdb.mission_time == 4121
assert hdb.humidity == 4350


def test_coordinates_data_block(coordinates_data_content: bytes) -> None:
"""Test that the coordinates data block is parsed correctly."""
cdb = CoordinatesDB.from_bytes(coordinates_data_content)

assert cdb.mission_time == 3340
assert cdb.latitude == 0
assert cdb.longitude == 0


def test_voltage_data_block(voltage_data_content: bytes) -> None:
"""Test that the voltage data block is parsed correctly."""
vdb = VoltageDB.from_bytes(voltage_data_content)
Expand Down

0 comments on commit 55ab33a

Please sign in to comment.