162 lines
5.0 KiB
Python
162 lines
5.0 KiB
Python
# core/sfp_structures.py
|
|
"""
|
|
Defines the ctypes Structures for the Simple Fragmentation Protocol (SFP)
|
|
and the application-specific image data format.
|
|
|
|
This centralizes data structure definitions, allowing them to be shared
|
|
between the transport layer (which uses SFPHeader) and the application
|
|
layer (which interprets the image-specific structures).
|
|
"""
|
|
|
|
import ctypes
|
|
|
|
# --- SFP Transport Layer Structures ---
|
|
|
|
class SFPHeader(ctypes.Structure):
|
|
"""Structure representing the SFP header (32 bytes)."""
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
("SFP_MARKER", ctypes.c_uint8),
|
|
("SFP_DIRECTION", ctypes.c_uint8),
|
|
("SFP_PROT_VER", ctypes.c_uint8),
|
|
("SFP_PT_SPARE", ctypes.c_uint8),
|
|
("SFP_TAG", ctypes.c_uint8),
|
|
("SFP_SRC", ctypes.c_uint8),
|
|
("SFP_FLOW", ctypes.c_uint8),
|
|
("SFP_TID", ctypes.c_uint8),
|
|
("SFP_FLAGS", ctypes.c_uint8),
|
|
("SFP_WIN", ctypes.c_uint8),
|
|
("SFP_ERR", ctypes.c_uint8),
|
|
("SFP_ERR_INFO", ctypes.c_uint8),
|
|
("SFP_TOTFRGAS", ctypes.c_uint16),
|
|
("SFP_FRAG", ctypes.c_uint16),
|
|
("SFP_RECTYPE", ctypes.c_uint8),
|
|
("SFP_RECSPARE", ctypes.c_uint8),
|
|
("SFP_PLDAP", ctypes.c_uint8),
|
|
("SFP_PLEXT", ctypes.c_uint8),
|
|
("SFP_RECCOUNTER", ctypes.c_uint16),
|
|
("SFP_PLSIZE", ctypes.c_uint16),
|
|
("SFP_TOTSIZE", ctypes.c_uint32),
|
|
("SFP_PLOFFSET", ctypes.c_uint32),
|
|
]
|
|
|
|
@classmethod
|
|
def size(cls):
|
|
"""Returns the size of the structure in bytes."""
|
|
return ctypes.sizeof(cls)
|
|
|
|
@staticmethod
|
|
def get_field_offset(field_name: str) -> int:
|
|
"""Returns the byte offset of a specific field within the structure."""
|
|
try:
|
|
return getattr(SFPHeader, field_name).offset
|
|
except AttributeError:
|
|
return -1
|
|
|
|
# --- Application Layer (Image Format) Structures ---
|
|
|
|
class DataTag(ctypes.Structure):
|
|
"""Structure representing a generic data tag (8 bytes)."""
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
("ID", ctypes.c_uint8 * 2),
|
|
("VALID", ctypes.c_uint8),
|
|
("VERSION", ctypes.c_uint8),
|
|
("SIZE", ctypes.c_uint32),
|
|
]
|
|
|
|
@classmethod
|
|
def size(cls):
|
|
"""Returns the size of the structure in bytes."""
|
|
return ctypes.sizeof(cls)
|
|
|
|
|
|
class HeaderData(ctypes.Structure):
|
|
"""Structure representing the HEADER_DATA block (~48 bytes)."""
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
("TYPE", ctypes.c_uint8),
|
|
("SUBTYPE", ctypes.c_uint8),
|
|
("LOGCOLORS", ctypes.c_uint8),
|
|
("IMG_RESERVED", ctypes.c_uint8),
|
|
("PRODINFO", ctypes.c_uint32 * 2),
|
|
("TOD", ctypes.c_uint16 * 2),
|
|
("RESERVED", ctypes.c_uint32),
|
|
("FCOUNTER", ctypes.c_uint32),
|
|
("TIMETAG", ctypes.c_uint32),
|
|
("NOMINALFRATE", ctypes.c_uint16),
|
|
("FRAMETAG", ctypes.c_uint16),
|
|
("OX", ctypes.c_uint16),
|
|
("OY", ctypes.c_uint16),
|
|
("DX", ctypes.c_uint16),
|
|
("DY", ctypes.c_uint16),
|
|
("STRIDE", ctypes.c_uint16),
|
|
("BPP", ctypes.c_uint8),
|
|
("COMP", ctypes.c_uint8),
|
|
("SPARE", ctypes.c_uint16),
|
|
("PALTYPE", ctypes.c_uint8),
|
|
("GAP", ctypes.c_uint8),
|
|
]
|
|
|
|
@classmethod
|
|
def size(cls):
|
|
"""Returns the size of the structure in bytes."""
|
|
return ctypes.sizeof(cls)
|
|
|
|
|
|
class GeoData(ctypes.Structure):
|
|
"""Structure representing the GEO_DATA block (~80 bytes)."""
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
("INVMASK", ctypes.c_uint32),
|
|
("ORIENTATION", ctypes.c_float),
|
|
("LATITUDE", ctypes.c_float),
|
|
("LONGITUDE", ctypes.c_float),
|
|
("REF_X", ctypes.c_uint16),
|
|
("REF_Y", ctypes.c_uint16),
|
|
("SCALE_X", ctypes.c_float),
|
|
("SCALE_Y", ctypes.c_float),
|
|
("POI_ORIENTATION", ctypes.c_float),
|
|
("POI_LATITUDE", ctypes.c_float),
|
|
("POI_LONGITUDE", ctypes.c_float),
|
|
("POI_ALTITUDE", ctypes.c_float),
|
|
("POI_X", ctypes.c_uint16),
|
|
("POI_Y", ctypes.c_uint16),
|
|
("SPARE", ctypes.c_uint32 * 7),
|
|
]
|
|
|
|
@classmethod
|
|
def size(cls):
|
|
"""Returns the size of the structure in bytes."""
|
|
return ctypes.sizeof(cls)
|
|
|
|
|
|
class ImageLeaderData(ctypes.Structure):
|
|
"""Represents the complete Image Leader data structure (~1320 bytes)."""
|
|
_pack_ = 1
|
|
_fields_ = [
|
|
("HEADER_TAG", DataTag),
|
|
("HEADER_DATA", HeaderData),
|
|
("GEO_TAG", DataTag),
|
|
("GEO_DATA", GeoData),
|
|
("RESERVED_TAG", DataTag),
|
|
("RESERVED_DATA", ctypes.c_uint8 * 128),
|
|
("CM_TAG", DataTag),
|
|
("COLOUR_MAP", ctypes.c_uint32 * 256),
|
|
("PIXEL_TAG", DataTag),
|
|
]
|
|
|
|
@classmethod
|
|
def size(cls):
|
|
"""Returns the size of the structure in bytes."""
|
|
return ctypes.sizeof(cls)
|
|
|
|
@staticmethod
|
|
def get_reserved_data_size() -> int:
|
|
"""Returns the static size of the RESERVED_DATA field."""
|
|
return 128
|
|
|
|
@staticmethod
|
|
def get_colour_map_size() -> int:
|
|
"""Returns the static size of the COLOUR_MAP field in bytes."""
|
|
return 1024 |