# CCSDS-NDM: CCSDS Navigation Data Messages Read/Write Library
#
# Copyright (C) Egemen Imre
#
# Licensed under GNU GPL v3.0. See LICENSE for more info.
"""
KVN handler registry for the ndmxml 2.0 schema.
Maps xsdata class name (str) → TypeHandler and root class name → dispatch
strategy. Classes absent from the registry implicitly use DEFAULT_HANDLER.
All-default types (no explicit entry needed)
--------------------------------------------
NdmHeader, OpmMetadata, OemMetadata, AemMetadata, OmmMetadata,
ApmMetadata, TdmMetadata, CdmMetadata,
StateVectorType (OPM — plain KEY=VALUE, not packed),
KeplerianElementsType, ManeuverParametersType,
SpacecraftParametersType, OdParametersType,
OpmCovarianceMatrixType (plain KEY=VALUE, no packed rows),
CdmCovarianceMatrixType (plain KEY=VALUE lower-triangular fields),
UserDefinedType, UserDefinedParameterType,
QuaternionType, QuaternionRateType,
QuaternionEphemerisType, QuaternionDerivativeType, QuaternionEulerRateType,
EulerAngleType, EulerAngleRateType,
SpinType, SpinNutationType,
and all scalar-with-units leaf types (PositionType, VelocityType, …).
Differences from ndmxml1
------------------------
- Covers OPM v2.0, OEM v2.0, OMM v2.0 (ndmxml1 has OPM v1.0 / OEM v2.0 but
different schema generation; ndmxml2 adds OMM v2.0).
- CDM covariance class is ``CdmCovarianceMatrixType`` (ndmxml1 uses
``CdmCovarianceType`` — same KVN structure, renamed in schema v2).
- APM and AEM are first introduced in ndmxml2 (ndmxml1 also defines them but
the mapping only routes AEMv1 / APMv1 through ndmxml2 classes).
- The registry and dispatch for this schema are structurally identical to
ndmxml1 because the special handler types share the same class names.
"""
from __future__ import annotations
from ccsds_ndm.kvn_handlers import (
DEFAULT_HANDLER,
DISPATCH_CDM,
DISPATCH_FLAT,
DISPATCH_SEGMENTED,
LOC_COVARIANCE,
LOC_DEFAULT,
LOC_PACKED_ATTITUDE,
LOC_PACKED_STATE,
LOC_TDM_OBS,
PARSE_COVARIANCE,
PARSE_PACKED_ATTITUDE,
PARSE_PACKED_STATE,
PARSE_ROTATION_ANGLE,
PARSE_ROTATION_RATE,
PARSE_TDM_OBS,
WRITE_COVARIANCE,
WRITE_PACKED_ATTITUDE,
WRITE_PACKED_STATE,
WRITE_ROTATION_ANGLE,
WRITE_ROTATION_RATE,
WRITE_TDM_OBS,
TypeHandler,
)
[docs]
class NdmXml2Registry:
"""KVN handler registry for the ndmxml 2.0 schema."""
def __init__(self) -> None:
self.version: int = 2
# NDM type ids that use segmented dispatch (META_START/STOP blocks)
self.segmented_ids: frozenset[str] = frozenset({"aem", "oem", "tdm"})
# NDM type ids that use CDM dispatch (split on OBJECT_1/OBJECT_2)
self.cdm_ids: frozenset[str] = frozenset({"cdm"})
# Maps xsdata class name → TypeHandler (absent → DEFAULT_HANDLER)
self.registry: dict[str, TypeHandler] = {
# -- OEM: packed epoch-led state vector rows
"StateVectorAccType": TypeHandler(
locate=LOC_PACKED_STATE,
parse=PARSE_PACKED_STATE,
write=WRITE_PACKED_STATE,
),
# -- AEM: packed attitude rows (column template from ctx['meta'].attitude_type)
"AttitudeStateType": TypeHandler(
locate=LOC_PACKED_ATTITUDE,
parse=PARSE_PACKED_ATTITUDE,
write=WRITE_PACKED_ATTITUDE,
),
# -- OEM covariance block (EPOCH line + lower-triangular numeric rows)
"OemCovarianceMatrixType": TypeHandler(
locate=LOC_COVARIANCE,
parse=PARSE_COVARIANCE,
write=WRITE_COVARIANCE,
),
# -- TDM observation lines: KEY = EPOCH VALUE
"TrackingDataObservationType": TypeHandler(
locate=LOC_TDM_OBS,
parse=PARSE_TDM_OBS,
write=WRITE_TDM_OBS,
),
# -- APM Euler angle container: keyword from rotation.angle discriminator
# (X_ANGLE / Y_ANGLE / Z_ANGLE); locate is default (keywords are in kw set)
"RotationAngleType": TypeHandler(
locate=LOC_DEFAULT,
parse=PARSE_ROTATION_ANGLE,
write=WRITE_ROTATION_ANGLE,
),
# -- APM Euler rate container: keyword from rotation.rate discriminator
# (X_RATE / Y_RATE / Z_RATE)
"RotationRateType": TypeHandler(
locate=LOC_DEFAULT,
parse=PARSE_ROTATION_RATE,
write=WRITE_ROTATION_RATE,
),
}
# Maps root class name → dispatch strategy sentinel
self.dispatch: dict[str, str] = {
# Flat: single segment, no META_START/STOP in KVN body
"Opm": DISPATCH_FLAT,
"Omm": DISPATCH_FLAT,
"Apm": DISPATCH_FLAT,
"Rdm": DISPATCH_FLAT,
# Segmented: META_START/META_STOP/DATA_START/DATA_STOP state machine
"Oem": DISPATCH_SEGMENTED,
"Aem": DISPATCH_SEGMENTED,
"Tdm": DISPATCH_SEGMENTED,
# Special CDM structure
"Cdm": DISPATCH_CDM,
}
[docs]
def get_handler(self, cls_name: str) -> TypeHandler:
"""Return the TypeHandler for ``cls_name``, falling back to DEFAULT_HANDLER."""
return self.registry.get(cls_name, DEFAULT_HANDLER)
# Module-level singleton
REGISTRY_INSTANCE = NdmXml2Registry()