""" Packet model for LoRa route simulation. Defines packet types and structure for HELLO, DATA, and ACK packets. Includes path tracing for multi-hop verification. """ from dataclasses import dataclass from enum import IntEnum from typing import Optional, List class PacketType(IntEnum): """Packet type enumeration.""" HELLO = 1 DATA = 2 ACK = 3 @dataclass class Packet: """ LoRa packet structure with path tracing. Attributes: type: Packet type (HELLO, DATA, or ACK) src: Source node ID dst: Destination node ID (-1 for broadcast) seq: Sequence number hop: Current hop count path: List of node IDs traversed (for multi-hop verification) payload: Optional payload data rssi: Received signal strength indicator (set on receive) """ type: PacketType src: int dst: int seq: int hop: int = 0 path: List[int] = None # Path trace for observability payload: Optional[str] = None rssi: Optional[float] = None def __post_init__(self): """Initialize path if not provided.""" if self.path is None: self.path = [self.src] def __repr__(self) -> str: return ( f"Packet({self.type.name}, src={self.src}, dst={self.dst}, " f"seq={self.seq}, hop={self.hop}, path={self.path})" ) def add_hop(self, node_id: int): """Add a node to the path and increment hop count.""" self.hop += 1 self.path.append(node_id) @property def is_broadcast(self) -> bool: """Check if packet is broadcast (dst = -1).""" return self.dst == -1 @property def is_hello(self) -> bool: """Check if packet is a HELLO packet.""" return self.type == PacketType.HELLO @property def is_data(self) -> bool: """Check if packet is a DATA packet.""" return self.type == PacketType.DATA @property def is_ack(self) -> bool: """Check if packet is an ACK packet.""" return self.type == PacketType.ACK @property def path_length(self) -> int: """Get the path length (number of hops).""" return len(self.path) - 1 if self.path else 0 def to_dict(self) -> dict: """Convert packet to dictionary for serialization.""" return { "type": self.type.name, "src": self.src, "dst": self.dst, "seq": self.seq, "hop": self.hop, "path": self.path, "payload": self.payload, "rssi": self.rssi, }