Repository: robamu-org/tmtccmd (language: python)

Issue:
Update from EIVE branch
- Bumped minimum required Python version to 3.8 so that `TypedDict`s can be used
- Moved all packet related code to a separate `spacepackets` package. This includes CFDP, ECSS and CCSDS code


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml
index 39c030e9..c93ef670 100644
--- a/.github/workflows/package.yml
+++ b/.github/workflows/package.yml
@@ -8,7 +8,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: [3.7, 3.8, 3.9]
+        python-version: [3.8, 3.9]
 
     steps:
     - uses: actions/checkout@v2
diff --git a/README.md b/README.md
index 54718478..f1550d94 100644
--- a/README.md
+++ b/README.md
@@ -3,6 +3,7 @@
 TMTC Commander Core [![Documentation Status](https://readthedocs.org/projects/tmtccmd/badge/?version=latest)](https://tmtccmd.readthedocs.io/en/latest/?badge=latest)
 [![package](https://github.com/spacefisch/tmtccmd/actions/workflows/package.yml/badge.svg)](https://github.com/spacefisch/tmtccmd/actions/workflows/package.yml)
 [![codecov](https://codecov.io/gh/robamu-org/tmtccmd/branch/develop/graph/badge.svg?token=BVOE3A4WE4)](https://codecov.io/gh/robamu-org/tmtccmd)
+[![PyPI version](https://badge.fury.io/py/tmtccmd.svg)](https://badge.fury.io/py/tmtccmd)
 ====
 
 ## Overview
@@ -70,7 +71,7 @@ On Ubuntu, if `pip` is not installed yet, you can install it with
 sudo apt-get install python3-pip
 ```
 
-It is recommended to use Python 3.8.
+The minimum allowed Python version is 3.8.
 For developers, it is recommended to add this repostiory as a submodule
 with the following command:
 
diff --git a/docs/README_PyPI.md b/docs/README_PyPI.md
index 1a8491f9..8d9aa68b 100644
--- a/docs/README_PyPI.md
+++ b/docs/README_PyPI.md
@@ -2,11 +2,12 @@
 
 TMTC Commander Core [![Documentation Status](https://readthedocs.org/projects/tmtccmd/badge/?version=latest)](https://tmtccmd.readthedocs.io/en/latest/?badge=latest)
 [![package](https://github.com/spacefisch/tmtccmd/actions/workflows/package.yml/badge.svg)](https://github.com/spacefisch/tmtccmd/actions/workflows/package.yml)
-[![codecov](https://codecov.io/gh/spacefisch/tmtccmd/branch/develop/graph/badge.svg?token=BVOE3A4WE4)](https://codecov.io/gh/spacefisch/tmtccmd)
+[![codecov](https://codecov.io/gh/robamu-org/tmtccmd/branch/develop/graph/badge.svg?token=BVOE3A4WE4)](https://codecov.io/gh/robamu-org/tmtccmd)
+[![PyPI version](https://badge.fury.io/py/tmtccmd.svg)](https://badge.fury.io/py/tmtccmd)
 ====
 
 ## Overview
 
-- Project Homepage: https://github.com/spacefisch/tmtccmd
+- Project Homepage: https://github.com/robamu-org/tmtccmd
 - Documentation: https://tmtccmd.readthedocs.io/en/latest/
 
diff --git a/docs/api/tmtccmd.ccsds.rst b/docs/api/tmtccmd.ccsds.rst
index b906fa6f..0fe7c06c 100644
--- a/docs/api/tmtccmd.ccsds.rst
+++ b/docs/api/tmtccmd.ccsds.rst
@@ -4,14 +4,6 @@ tmtccmd.ccsds package
 Submodules
 ----------
 
-tmtccmd.ccsds.spacepacket module
---------------------------------
-
-.. automodule:: tmtccmd.ccsds.spacepacket
-   :members:
-   :undoc-members:
-   :show-inheritance:
-
 tmtccmd.ccsds.handler module
 --------------------------------
 
diff --git a/docs/api/tmtccmd.ecss.rst b/docs/api/tmtccmd.ecss.rst
deleted file mode 100644
index 13519a06..00000000
--- a/docs/api/tmtccmd.ecss.rst
+++ /dev/null
@@ -1,45 +0,0 @@
-tmtccmd.ecss package
-====================
-
-Submodules
-----------
-
-tmtccmd.ecss.conf module
-------------------------
-
-.. automodule:: tmtccmd.ecss.conf
-   :members:
-   :undoc-members:
-   :show-inheritance:
-
-tmtccmd.ecss.tc module
-----------------------
-
-.. automodule:: tmtccmd.ecss.tc
-   :members:
-   :undoc-members:
-   :show-inheritance:
-
-tmtccmd.ecss.tm module
-----------------------
-
-.. automodule:: tmtccmd.ecss.tm
-   :members:
-   :undoc-members:
-   :show-inheritance:
-
-tmtccmd.ecss.tm\_creator module
--------------------------------
-
-.. automodule:: tmtccmd.ecss.tm_creator
-   :members:
-   :undoc-members:
-   :show-inheritance:
-
-Module contents
----------------
-
-.. automodule:: tmtccmd.ecss
-   :members:
-   :undoc-members:
-   :show-inheritance:
diff --git a/setup.cfg b/setup.cfg
index b5c68a26..db2a6278 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -18,8 +18,8 @@ classifiers =
 	Operating System :: POSIX
 	Operating System :: Microsoft :: Windows
 	Programming Language :: Python :: 3
-	Programming Language :: Python :: 3.7
 	Programming Language :: Python :: 3.8
+	Programming Language :: Python :: 3.9
 	Topic :: Communications
 	Topic :: Software Development :: Libraries
 	Topic :: Software Development :: Libraries :: Python Modules
@@ -31,11 +31,12 @@ install_requires =
 	pyserial>=3.0
 	colorama>=0.4.4
 	colorlog>=5.0.0
-	dle-encoder>=0.2.0
+	dle-encoder>=0.2
+	spacepackets>=0.2
 package_dir =
     = src
 packages = find:
-python_requires = >=3.7
+python_requires = >=3.8
 
 [options.packages.find]
 where = src
diff --git a/src/tmtccmd/__init__.py b/src/tmtccmd/__init__.py
index 6be8bf7e..ffd2be5e 100644
--- a/src/tmtccmd/__init__.py
+++ b/src/tmtccmd/__init__.py
@@ -1,8 +1,8 @@
 VERSION_NAME = "tmtccmd"
 VERSION_MAJOR = 1
-VERSION_MINOR = 8
-VERSION_REVISION = 0
+VERSION_MINOR = 9
+VERSION_REVISION = 1
 
 # I think this needs to be in string representation to be parsed so we can't
 # use a formatted string here.
-__version__ = "1.8.0"
+__version__ = "1.9.1"
diff --git a/src/tmtccmd/ccsds/log.py b/src/tmtccmd/ccsds/log.py
deleted file mode 100644
index 3d8cff89..00000000
--- a/src/tmtccmd/ccsds/log.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""In case ECSS and CFDP code go into a separate pyton package, this layer can be adapted
-to use a different logger (e.g. default logger)
-"""
-from tmtccmd.utility.logger import get_console_logger
-
-LOGGER = get_console_logger()
diff --git a/src/tmtccmd/ccsds/spacepacket.py b/src/tmtccmd/ccsds/spacepacket.py
deleted file mode 100644
index 73564214..00000000
--- a/src/tmtccmd/ccsds/spacepacket.py
+++ /dev/null
@@ -1,263 +0,0 @@
-from __future__ import annotations
-import enum
-
-from typing import Tuple, Deque, List
-from tmtccmd.ccsds.log import LOGGER
-
-SPACE_PACKET_HEADER_SIZE = 6
-
-
-class PacketTypes(enum.IntEnum):
-    PACKET_TYPE_TM = 0
-    PACKET_TYPE_TC = 1
-
-
-class SequenceFlags(enum.IntEnum):
-    CONTINUATION_SEGMENT = 0b00,
-    FIRST_SEGMENT = 0b01,
-    LAST_SEGMENT = 0b10,
-    UNSEGMENTED = 0b11
-
-
-class SpacePacketHeader:
-    """This class encapsulates the space packet header. Packet reference: Blue Book CCSDS 133.0-B-2
-    """
-    def __init__(
-            self, packet_type: PacketTypes, apid: int, source_sequence_count: int, data_length: int,
-            packet_version: int = 0b000, secondary_header_flag: bool = True,
-            sequence_flags: int = 0b11
-    ):
-        self.packet_type = packet_type
-        self.apid = apid
-        self.ssc = source_sequence_count
-        self.secondary_header_flag = secondary_header_flag
-        self.sequence_flags = sequence_flags
-        self.psc = get_space_packet_sequence_control(
-            sequence_flags=self.sequence_flags, source_sequence_count=self.ssc
-        )
-        self.version = packet_version
-        self.data_length = data_length
-        self.packet_id = get_space_packet_id_num(
-            packet_type=self.packet_type, secondary_header_flag=self.secondary_header_flag,
-            apid=self.apid
-        )
-
-    @classmethod
-    def __empty(cls) -> SpacePacketHeader:
-        return SpacePacketHeader(
-            packet_type=PacketTypes.PACKET_TYPE_TC,
-            apid=0,
-            source_sequence_count=0,
-            data_length=0
-        )
-
-    def pack(self) -> bytearray:
-        """Serialize raw space packet header.
-        :param packet_type: 0 for telemetry, 1 for telecommands
-        :param data_length: Length of packet data field
-        :param source_sequence_count:
-        :param secondary_header_flag: Indicates presence of absence of a
-        Secondary Header in the Space Packet
-        :param version: Shall be b000 for CCSDS Version 1 packets
-        :param sequence_flags: 0b11 for stand-alone packets (unsegmented user data)
-        :param apid:
-        """
-        header = bytearray()
-        header.append((self.packet_id & 0xff00) >> 8)
-        header.append(self.packet_id & 0xff)
-        header.append((self.psc & 0xff00) >> 8)
-        header.append(self.psc & 0xff)
-        header.append((self.data_length & 0xff00) >> 8)
-        header.append(self.data_length & 0xff)
-        return header
-
-    @classmethod
-    def unpack(cls, space_packet_raw: bytes) -> SpacePacketHeader:
-        """Unpack a raw space packet into the space packet header
-        :raise ValueError: Raw packet length invalid"""
-        if len(space_packet_raw) < SPACE_PACKET_HEADER_SIZE:
-            LOGGER.warning('Packet size smaller than PUS header size!')
-            raise ValueError
-        packet_type = space_packet_raw[0] & 0x10
-        if packet_type == 0:
-            packet_type = PacketTypes.PACKET_TYPE_TM
-        else:
-            packet_type = PacketTypes.PACKET_TYPE_TC
-        packet_version = space_packet_raw[0] >> 5
-        secondary_header_flag = (space_packet_raw[0] & 0x8) >> 3
-        apid = ((space_packet_raw[0] & 0x7) << 8) | space_packet_raw[1]
-        sequence_flags = (space_packet_raw[2] & 0xC0) >> 6
-        ssc = ((space_packet_raw[2] << 8) | space_packet_raw[3]) & 0x3fff
-        data_length = space_packet_raw[4] << 8 | space_packet_raw[5]
-        return SpacePacketHeader(
-            packet_type=packet_type,
-            apid=apid,
-            secondary_header_flag=secondary_header_flag,
-            packet_version=packet_version,
-            data_length=data_length,
-            sequence_flags=sequence_flags,
-            source_sequence_count=ssc
-        )
-
-    def append_space_packet_header_content(self, content_list: list):
-        content_list.append(str(hex(self.apid)))
-        content_list.append(str(self.ssc))
-
-    @staticmethod
-    def append_space_packet_header_column_headers(header_list: list):
-        header_list.append("APID")
-        header_list.append("SSC")
-
-
-def get_space_packet_id_bytes(
-        packet_type: PacketTypes, secondary_header_flag: True, apid: int, version: int = 0b000
-) -> Tuple[int, int]:
-    """This function also includes the first three bits reserved for the version.
-
-    :param version: Version field of the packet ID. Defined to be 0b000 in the space packet standard
-    :param packet_type:
-    :param secondary_header_flag: Indicates presence of absence of a Secondary Header
-    in the Space Packet
-    :param apid: Application Process Identifier. Naming mechanism for managed data path, has 11 bits
-    :return:
-    """
-    byte_one = \
-        ((version << 5) & 0xE0) | ((packet_type & 0x01) << 4) | \
-        ((int(secondary_header_flag) & 0x01) << 3) | ((apid & 0x700) >> 8)
-    byte_two = apid & 0xFF
-    return byte_one, byte_two
-
-
-def get_space_packet_id_num(
-        packet_type: PacketTypes, secondary_header_flag: bool, apid: int
-) -> int:
-    """Get packet identification segment of packet primary header in integer format"""
-    return ((packet_type << 12 | int(secondary_header_flag) << 11 | apid) & 0x1fff)
-
-
-def get_space_packet_sequence_control(
-        sequence_flags: SequenceFlags, source_sequence_count: int
-) -> int:
-    """ """
-    if sequence_flags > 3:
-        print(
-            "get_sp_packet_sequence_control: Sequence flag value larger than 0b11! Setting to 0b11.."
-        )
-        sequence_flags = SequenceFlags.UNSEGMENTED
-    if source_sequence_count > 0x3fff:
-        print(
-            "get_sp_packet_sequence_control: Source sequence count largen than 0x3fff. Larger bits are cut off!"
-        )
-    return (source_sequence_count & 0x3FFF) | (sequence_flags << 14)
-
-
-def get_space_packet_header(
-        packet_id: int, packet_sequence_control: int, data_length: int
-) -> bytearray:
-    header = bytearray()
-    header.append((packet_id & 0xff00) >> 8)
-    header.append(packet_id & 0xff)
-    header.append((packet_sequence_control & 0xff00) >> 8)
-    header.append(packet_sequence_control & 0xff)
-    header.append((data_length & 0xff00) >> 8)
-    header.append(data_length & 0xff)
-    return header
-
-
-def get_space_packet_header_from_packet_id_bytes(
-        packet_id_byte_one: int, packet_id_byte_two: int, packet_sequence_control: int,
-        data_length: int
-) -> bytearray:
-    header = bytearray()
-    header.append(packet_id_byte_one)
-    header.append(packet_id_byte_two)
-    header.append((packet_sequence_control & 0xFF00) >> 8)
-    header.append(packet_sequence_control & 0xFF)
-    header.append((data_length & 0xFF00) >> 8)
-    header.append(data_length & 0xFF)
-    return header
-
-
-def get_apid_from_raw_space_packet(raw_packet: bytes) -> int:
-    if len(raw_packet) < 6:
-        return 0
-    return ((raw_packet[0] & 0x7) << 8) | raw_packet[1]
-
-
-def get_total_space_packet_len_from_len_field(len_field: int):
-    """Definition of length field is: C = (Octets in data field - 1).
-    Therefore, octets in data field in len_field plus one. The total space packet length
-    is therefore len_field plus one plus the space packet header size (6)"""
-    return len_field + SPACE_PACKET_HEADER_SIZE + 1
-
-
-def parse_space_packets(
-        analysis_queue: Deque[bytearray], packet_id: int, max_len: int
-) -> List[bytearray]:
-    """Given a deque of bytearrays, parse for space packets. Any broken headers will be removed.
-    Any broken tail packets will be reinserted into the given deque
-    :param analysis_queue:
-    :param packet_id:
-    :param max_len:     Maximum allowed packet length
-    :return:
-    """
-    tm_list = []
-    concatenated_packets = bytearray()
-    if not analysis_queue:
-        return tm_list
-    while analysis_queue:
-        # Put it all in one buffer
-        concatenated_packets.extend(analysis_queue.pop())
-    current_idx = 0
-    if len(concatenated_packets) < 6:
-        return tm_list
-    # Packet ID detected
-    while True:
-        if current_idx > max_len - 6 or current_idx > len(concatenated_packets) - 1:
-            break
-        try:
-            current_packet_id = \
-                (concatenated_packets[current_idx] << 8) | concatenated_packets[current_idx + 1]
-        except IndexError:
-            LOGGER.warning(
-                f'Index error, current index {current_idx} larger than length of concatenated '
-                f'packets {len(concatenated_packets)}'
-            )
-            return tm_list
-        if current_packet_id == packet_id:
-            result, current_idx = __handle_packet_id_match(
-                concatenated_packets=concatenated_packets, analysis_queue=analysis_queue,
-                max_len=max_len, current_idx=current_idx, tm_list=tm_list
-            )
-            if result != 0:
-                break
-        else:
-            # Keep parsing until a packet ID is found
-            current_idx += 1
-    return tm_list
-
-
-def __handle_packet_id_match(
-        concatenated_packets: bytearray, analysis_queue: Deque[bytearray], max_len: int,
-        current_idx: int, tm_list: List[bytearray]
-) -> (int, int):
-    next_packet_len_field = \
-        concatenated_packets[current_idx + 4] | concatenated_packets[current_idx + 5]
-    total_packet_len = get_total_space_packet_len_from_len_field(next_packet_len_field)
-    if total_packet_len > max_len:
-        print(
-            f'parse_space_packets: Detected packet length larger than specified maximum'
-            f'length {max_len}. Skipping header..'
-        )
-        # Packet too long. Throw away the header and advance index
-        current_idx += 6
-    # Might be part of packet. Put back into analysis queue as whole
-    elif total_packet_len > len(concatenated_packets):
-        analysis_queue.appendleft(concatenated_packets)
-        return -1, current_idx
-    else:
-        tm_list.append(
-            concatenated_packets[current_idx: current_idx + total_packet_len]
-        )
-        current_idx += total_packet_len
-    return 0, current_idx
diff --git a/src/tmtccmd/ccsds/time.py b/src/tmtccmd/ccsds/time.py
deleted file mode 100644
index c4da074a..00000000
--- a/src/tmtccmd/ccsds/time.py
+++ /dev/null
@@ -1,152 +0,0 @@
-from __future__ import annotations
-import datetime
-import math
-import enum
-import time
-from abc import abstractmethod
-
-DAYS_CCSDS_TO_UNIX = -4383
-SECONDS_PER_DAY = 86400
-UNIX_EPOCH = datetime.datetime.utcfromtimestamp(0)
-
-
-class CcsdsTimeCodeId(enum.IntEnum):
-    NONE = 0
-    CUC_CCSDS_EPOCH = 0b001
-    CUC_AGENCY_EPOCH = 0b010
-    CDS = 0b100
-    CCS = 0b101
-
-
-def convert_unix_days_to_ccsds_days(unix_days: int) -> int:
-    """Convert Unix days to CCSDS days
-
-    CCSDS epoch: 1958 Januar 1
-    Unix epoch: 1970 January 1
-    """
-    return unix_days - DAYS_CCSDS_TO_UNIX
-
-
-def convert_ccsds_days_to_unix_days(ccsds_days: int) -> int:
-    """Convert CCSDS days to Unix days
-
-    CCSDS epoch: 1958 Januar 1
-    Unix epoch: 1970 January 1
-    """
-    return ccsds_days + DAYS_CCSDS_TO_UNIX
-
-
-def read_p_field(p_field: int) -> CcsdsTimeCodeId:
-    """Read the p field and return the CCSDS Time Code ID
-    :param p_field:
-    :return:
-    :raise IndexError: P field has invalid value
-    """
-    return CcsdsTimeCodeId((p_field & 0x70) >> 4)
-
-
-class CcsdsTimeCode:
-    @abstractmethod
-    def pack(self) -> bytearray:
-        self.ccsds_id = CcsdsTimeCodeId.NONE
-        return bytearray()
-
-    @abstractmethod
-    def return_unix_seconds(self) -> int:
-        return 0
-
-    @abstractmethod
-    def return_time_string(self) -> str:
-        return ''
-
-    def add_time_to_content_list(self, content_list: list):
-        content_list.append(self.return_unix_seconds())
-        content_list.append(self.return_time_string())
-
-    @staticmethod
-    def add_time_headers_to_header_list(header_list: list):
-        header_list.append("OBSWTime (s)")
-        header_list.append("Time")
-
-
-class CdsShortTimestamp(CcsdsTimeCode):
-    """Unpacks the time datafield of the TM packet. Right now, CDS Short timeformat is used,
-    and the size of the time stamp is expected to be seven bytes.
-    """
-    CDS_SHORT_ID = 0b100
-    TIMESTAMP_SIZE = 7
-
-    def __init__(self, ccsds_days: int, ms_of_day: int):
-        self.ccsds_id = CcsdsTimeCodeId.CDS
-        self.p_field = CdsShortTimestamp.CDS_SHORT_ID << 4
-        # CCSDS recommends a 1958 Januar 1 epoch, which is different from the Unix epoch
-        self.ccsds_days = ccsds_days
-        self.unix_days = convert_ccsds_days_to_unix_days(self.ccsds_days)
-        self.unix_seconds = self.unix_days * (24 * 60 * 60)
-        self.ms_of_day = ms_of_day
-        self.seconds_of_day = self.ms_of_day / 1000.0
-        self.unix_seconds += self.seconds_of_day
-        if self.unix_seconds < 0:
-            date = datetime.datetime(1970, 1, 1) + datetime.timedelta(seconds=self.unix_seconds)
-        else:
-            date = datetime.datetime.utcfromtimestamp(self.unix_seconds)
-        self.time_string = date.strftime("%Y-%m-%d %H:%M:%S.%f")
-
-    @classmethod
-    def init_from_unix_days(cls, unix_days: int, ms_of_day: int) -> CdsShortTimestamp:
-        return cls(
-            ccsds_days=convert_unix_days_to_ccsds_days(unix_days=unix_days),
-            ms_of_day=ms_of_day
-        )
-
-    @classmethod
-    def __empty(cls):
-        return cls(
-            ccsds_days=0,
-            ms_of_day=0
-        )
-
-    def pack(self) -> bytearray:
-        cds_packet = bytearray()
-        cds_packet.append(self.p_field)
-        cds_packet.append((self.ccsds_days & 0xff00) >> 8)
-        cds_packet.append(self.ccsds_days & 0xff)
-        cds_packet.append((self.ms_of_day & 0xff000000) >> 24)
-        cds_packet.append((self.ms_of_day & 0x00ff0000) >> 16)
-        cds_packet.append((self.ms_of_day & 0x0000ff00) >> 8)
-        cds_packet.append(self.ms_of_day & 0x000000ff)
-        return cds_packet
-
-    @classmethod
-    def unpack(cls, time_field: bytearray) -> CdsShortTimestamp:
-        if len(time_field) < cls.TIMESTAMP_SIZE:
-            raise ValueError
-        # TODO: check ID?
-        p_field = time_field[0]
-        ccsds_days = ((time_field[1] << 8) | (time_field[2]))
-        ms_of_day = \
-            ((time_field[3] << 24) | (time_field[4] << 16) | (time_field[5]) << 8 | time_field[6])
-        return cls(
-            ccsds_days=ccsds_days,
-            ms_of_day=ms_of_day
-        )
-
-    @staticmethod
-    def init_from_current_time() -> CdsShortTimestamp:
-        """Returns a seven byte CDS short timestamp with the current time"""
-        unix_days = (datetime.datetime.utcnow() - UNIX_EPOCH).days
-        seconds = time.time()
-        fraction_ms = seconds - math.floor(seconds)
-        days_ms = int((seconds % SECONDS_PER_DAY) * 1000 + fraction_ms)
-        time_packet = CdsShortTimestamp.init_from_unix_days(
-            unix_days=unix_days, ms_of_day=days_ms
-        )
-        return time_packet
-
-    @abstractmethod
-    def return_unix_seconds(self) -> int:
-        return self.unix_seconds
-
-    @abstractmethod
-    def return_time_string(self) -> str:
-        return self.time_string
diff --git a/src/tmtccmd/cfdp/__init__.py b/src/tmtccmd/cfdp/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmtccmd/cfdp/conf.py b/src/tmtccmd/cfdp/conf.py
deleted file mode 100644
index cad69568..00000000
--- a/src/tmtccmd/cfdp/conf.py
+++ /dev/null
@@ -1,58 +0,0 @@
-import enum
-from tmtccmd.cfdp.definitions import LenInBytes
-from tmtccmd.ccsds.log import LOGGER
-
-
-class CfdpConfKeys(enum.IntEnum):
-    LEN_ENTITY_ID = 0
-    LEN_TRANSACTION_SEQ_NUM = 1
-    WITH_CRC_CONFIG_ID = 2
-
-
-__CFDP_DICT = {
-    CfdpConfKeys.LEN_ENTITY_ID: LenInBytes.FOUR_BYTES,
-    CfdpConfKeys.LEN_TRANSACTION_SEQ_NUM: LenInBytes.TWO_BYTES,
-    CfdpConfKeys.CRC_CONFIG_ID: True
-}
-
-
-def set_default_length_entity_id(new_len: int):
-    __CFDP_DICT[CfdpConfKeys.LEN_ENTITY_ID] = new_len
-
-
-def get_default_length_entity_id() -> int:
-    return __CFDP_DICT[CfdpConfKeys.LEN_ENTITY_ID]
-
-
-def set_default_length_transaction_seq_num(new_len: int):
-    __CFDP_DICT[CfdpConfKeys.LEN_TRANSACTION_SEQ_NUM] = new_len
-
-
-def get_default_length_transaction_seq_num() -> int:
-    return __CFDP_DICT[CfdpConfKeys.LEN_TRANSACTION_SEQ_NUM]
-
-
-def set_default_pdu_crc_mode(with_crc: bool):
-    __CFDP_DICT[CfdpConfKeys.WITH_CRC_CONFIG_ID] = with_crc
-
-
-def get_default_pdu_crc_mode() -> bool:
-    return __CFDP_DICT[CfdpConfKeys.WITH_CRC_CONFIG_ID]
-
-
-def check_packet_length(raw_packet_len: int, min_len: int, warn_on_fail: bool = True) -> bool:
-    """Check whether the length of a raw packet is shorter than a specified expectedminimum length.
-    By defaults, prints a warning if this is the case
-    :param raw_packet_len:
-    :param min_len:
-    :param warn_on_fail:
-    :return: Returns True if the raw packet is larger than the specified minimum length, False
-    otherwise
-    """
-    if raw_packet_len < min_len:
-        if warn_on_fail:
-            LOGGER.warning(
-                f'Detected packet length {raw_packet_len}, smaller than expected {min_len}'
-            )
-        return False
-    return True
diff --git a/src/tmtccmd/cfdp/definitions.py b/src/tmtccmd/cfdp/definitions.py
deleted file mode 100644
index 2dda70d3..00000000
--- a/src/tmtccmd/cfdp/definitions.py
+++ /dev/null
@@ -1,17 +0,0 @@
-import enum
-
-
-class LenInBytes(enum.IntEnum):
-    ONE_BYTE = 0
-    TWO_BYTES = 1
-    THREE_BYTES = 2
-    FOUR_BYTES = 3
-    FIVE_BYTES = 4
-    SIX_BYTES = 5
-    SEVEN_BYTES = 6
-    EIGHT_BYTES = 7
-    NONE = 99
-
-
-class ChecksumTypes(enum.IntEnum):
-    pass
diff --git a/src/tmtccmd/cfdp/lv.py b/src/tmtccmd/cfdp/lv.py
deleted file mode 100644
index 5e37da91..00000000
--- a/src/tmtccmd/cfdp/lv.py
+++ /dev/null
@@ -1,39 +0,0 @@
-from __future__ import annotations
-from tmtccmd.ccsds.log import LOGGER
-
-
-class CfdpLv:
-    def __init__(self, value: bytearray):
-        """This class encapsulates CFDP LV fields
-        :raise ValueError: If value is invalid and serilization is enabled or if length of bytearray
-        is too large
-        :param serialize:
-        :param value:
-        """
-        if len(value) > 255:
-            LOGGER.warning('Length too large for LV field')
-            raise ValueError
-        self.len = len(value)
-        self.value = value
-
-    def get_len(self):
-        """Returns length of full LV packet"""
-        return self.len + 1
-
-    def pack(self):
-        packet = bytearray()
-        packet.append(self.len)
-        packet.extend(self.value)
-
-    @classmethod
-    def unpack(cls, raw_bytes: bytearray) -> CfdpLv:
-        """Parses LV field at the start of the given bytearray
-        :raise ValueError: Invalid length found
-        """
-        detected_len = raw_bytes[0]
-        if detected_len > 255:
-            LOGGER.warning('Length too large for LV field')
-            raise ValueError
-        return cls(
-            value=raw_bytes[1:]
-        )
diff --git a/src/tmtccmd/cfdp/pdu/__init__.py b/src/tmtccmd/cfdp/pdu/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmtccmd/cfdp/pdu/ack.py b/src/tmtccmd/cfdp/pdu/ack.py
deleted file mode 100644
index cd9d8e30..00000000
--- a/src/tmtccmd/cfdp/pdu/ack.py
+++ /dev/null
@@ -1,75 +0,0 @@
-from __future__ import annotations
-import enum
-import struct
-
-from tmtccmd.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveCodes, \
-    ConditionCode
-from tmtccmd.cfdp.pdu.header import Direction, TransmissionModes, CrcFlag
-from tmtccmd.cfdp.tlv import CfdpTlv
-from tmtccmd.cfdp.conf import LenInBytes, check_packet_length
-from tmtccmd.ccsds.log import LOGGER
-
-
-class TransactionStatus(enum.IntEnum):
-    """For more detailed information: CCSDS 727.0-B-5 p.81"""
-    UNDEFINED = 0b00
-    ACTIVE = 0b01
-    TERMINATED = 0b10
-    UNRECOGNIZED = 0b11
-
-
-class AckPdu():
-    def __init__(
-        self,
-        directive_code_of_acked_pdu: DirectiveCodes,
-        condition_code_of_acked_pdu: ConditionCode,
-        transaction_status: TransactionStatus,
-        direction: Direction,
-        trans_mode: TransmissionModes,
-        crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-        len_entity_id: LenInBytes = LenInBytes.NONE,
-        len_transaction_seq_num=LenInBytes.NONE,
-    ):
-        self.pdu_file_directive = FileDirectivePduBase(
-            directive_code=DirectiveCodes.ACK_PDU,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.directive_code_of_acked_pdu = directive_code_of_acked_pdu
-        self.directive_subtype_code = 0
-        if self.directive_code_of_acked_pdu == DirectiveCodes.FINISHED_PDU:
-            self.directive_subtype_code = 0b0001
-        else:
-            self.directive_subtype_code = 0b0000
-        self.condition_code_of_acked_pdu = condition_code_of_acked_pdu
-        self.transaction_status = transaction_status
-
-    @classmethod
-    def __empty(cls) -> AckPdu:
-        return cls(
-            directive_code_of_acked_pdu=None,
-            condition_code_of_acked_pdu=None,
-            transaction_status=None,
-            direction=None,
-            trans_mode=None
-        )
-
-    def pack(self):
-        packet = self.pdu_file_directive.pack()
-        packet.append((self.directive_code_of_acked_pdu << 4) | self.directive_subtype_code)
-        packet.append((self.condition_code_of_acked_pdu << 4) | self.transaction_status)
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> AckPdu:
-        ack_packet = cls.__empty()
-        ack_packet.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=raw_packet)
-        current_idx = ack_packet.pdu_file_directive.get_len()
-        ack_packet.directive_code_of_acked_pdu = raw_packet[current_idx] & 0xf0
-        ack_packet.directive_subtype_code = raw_packet[current_idx] & 0x0f
-        current_idx += 1
-        ack_packet.condition_code_of_acked_pdu = raw_packet[current_idx] & 0xf0
-        ack_packet.transaction_status = raw_packet[current_idx] & 0x03
-        return ack_packet
diff --git a/src/tmtccmd/cfdp/pdu/eof.py b/src/tmtccmd/cfdp/pdu/eof.py
deleted file mode 100644
index 036fcd7e..00000000
--- a/src/tmtccmd/cfdp/pdu/eof.py
+++ /dev/null
@@ -1,87 +0,0 @@
-from __future__ import annotations
-import struct
-
-from tmtccmd.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveCodes, \
-    ConditionCode
-from tmtccmd.cfdp.pdu.header import Direction, TransmissionModes, CrcFlag
-from tmtccmd.cfdp.tlv import CfdpTlv
-from tmtccmd.cfdp.conf import LenInBytes, check_packet_length
-from tmtccmd.ccsds.log import LOGGER
-
-
-class EofPdu():
-    MINIMAL_LENGTH = FileDirectivePduBase.FILE_DIRECTIVE_PDU_LEN + 1 + 4 + 4
-
-    def __init__(
-        self,
-        file_checksum: int,
-        file_size: int,
-        direction: Direction,
-        trans_mode: TransmissionModes,
-        crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-        fault_location: CfdpTlv = None,
-        condition_code: ConditionCode = ConditionCode.NO_ERROR,
-        len_entity_id: LenInBytes = LenInBytes.NONE,
-        len_transaction_seq_num=LenInBytes.NONE,
-    ):
-        self.pdu_file_directive = FileDirectivePduBase(
-            directive_code=DirectiveCodes.EOF_PDU,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.condition_code = condition_code
-        self.file_checksum = file_checksum
-        self.file_size = file_size
-        self.fault_location = fault_location
-
-    @classmethod
-    def __empty(cls) -> EofPdu:
-        cls(
-            file_checksum=None,
-            file_size=None,
-            direction=None,
-            trans_mode=None
-        )
-
-    def pack(self) -> bytearray:
-        eof_pdu = bytearray()
-        eof_pdu.extend(self.pdu_file_directive.pack())
-        eof_pdu.append(self.condition_code << 4)
-        eof_pdu.extend(struct.pack('!I', self.file_checksum))
-        if self.pdu_file_directive.pdu_header.large_file:
-            eof_pdu.extend(struct.pack('!Q', self.file_size))
-        else:
-            eof_pdu.extend(struct.pack('!I', self.file_size))
-        if self.fault_location is not None:
-            eof_pdu.extend(self.fault_location.pack())
-        return eof_pdu
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> EofPdu:
-        """Deserialize raw EOF PDU packet
-        :param raw_packet:
-        :raise ValueError: If raw packet is too short
-        :return:
-        """
-        eof_pdu = cls.__empty()
-        eof_pdu.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=raw_packet)
-        expected_min_len = cls.MINIMAL_LENGTH
-        if not check_packet_length(raw_packet_len=len(raw_packet), min_len=expected_min_len):
-            raise ValueError
-        current_idx = eof_pdu.pdu_file_directive.get_len()
-        eof_pdu.condition_code = raw_packet[current_idx] & 0xf0
-        expected_min_len = eof_pdu.pdu_file_directive.get_len() + 5
-        current_idx += 1
-        checksum_raw = raw_packet[current_idx: current_idx + 4]
-        eof_pdu.file_checksum = struct.unpack('!I', checksum_raw)[0]
-        current_idx += 4
-        current_idx, eof_pdu.file_size = eof_pdu.pdu_file_directive.parse_fss_field(
-            raw_packet=raw_packet, current_idx=current_idx
-        )
-        if len(raw_packet) > current_idx:
-            eof_pdu.fault_location = CfdpTlv(serialize=False)
-            eof_pdu.fault_location.unpack(raw_bytes=raw_packet[current_idx:])
-        return eof_pdu
diff --git a/src/tmtccmd/cfdp/pdu/file_directive.py b/src/tmtccmd/cfdp/pdu/file_directive.py
deleted file mode 100644
index 4cb3ec9b..00000000
--- a/src/tmtccmd/cfdp/pdu/file_directive.py
+++ /dev/null
@@ -1,119 +0,0 @@
-from __future__ import annotations
-import enum
-import struct
-
-from tmtccmd.cfdp.pdu.header import PduHeader, PduType, Direction, CrcFlag, TransmissionModes
-from tmtccmd.cfdp.conf import check_packet_length
-from tmtccmd.cfdp.definitions import LenInBytes
-from tmtccmd.ccsds.log import LOGGER
-
-
-class DirectiveCodes(enum.IntEnum):
-    EOF_PDU = 0x04
-    FINISHED_PDU = 0x05
-    ACK_PDU = 0x06
-    METADATA_PDU = 0x07
-    NAK_PDU = 0x08
-    PROMPT_PDU = 0x09
-    KEEP_ALIVE_PDU = 0x0C
-
-
-class ConditionCode(enum.IntEnum):
-    NO_CONDITION_FIELD = -1
-    NO_ERROR = 0b0000
-    POSITIVE_ACK_LIMIT_REACHED = 0b0001
-    KEEP_ALIVE_LIMIT_REACHED = 0b0010
-    INVALID_TRANSMISSION_MODE = 0b0011
-    FILESTORE_REJECTION = 0b0100
-    FILE_CHECKSUM_FAILURE = 0b0101
-    FILE_SIZE_ERROR = 0b0110
-    NAK_LIMIT_REACHED = 0b0111
-    INACTIVITY_DETECTED = 0b1000
-    CHECK_LIMIT_REACHED = 0b1010
-    UNSUPPORTED_CHECKSUM_TYPE = 0b1011
-    SUSPEND_REQUEST_RECEIVED = 0b1110
-    CANCEL_REQUEST_RECEIVED = 0b1111
-
-
-class FileDirectivePduBase:
-    FILE_DIRECTIVE_PDU_LEN = 5
-    """Base class for file directive PDUs encapsulating all its common components.
-    All other file directive PDU classes implement this class
-    """
-    def __init__(
-            self,
-            directive_code: DirectiveCodes,
-            # PDU Header parameters
-            direction: Direction,
-            trans_mode: TransmissionModes,
-            crc_flag: CrcFlag,
-            len_entity_id: LenInBytes = LenInBytes.NONE,
-            len_transaction_seq_num: LenInBytes = LenInBytes.NONE,
-    ):
-        self.pdu_header = PduHeader(
-            pdu_type=PduType.FILE_DIRECTIVE,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.directive_code = directive_code
-
-    @classmethod
-    def __empty(cls) -> FileDirectivePduBase:
-        return cls(
-            directive_code=None,
-            direction=None,
-            trans_mode=None,
-            crc_flag=None
-        )
-
-    def get_len(self) -> int:
-        return self.FILE_DIRECTIVE_PDU_LEN
-
-    def pack(self) -> bytearray:
-        data = bytearray()
-        data.extend(self.pdu_header.pack())
-        data.append(self.directive_code)
-        return data
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> FileDirectivePduBase:
-        """Unpack a raw bytearray into the File Directive PDU object representation
-        :param raw_bytes:
-        :raise ValueError: Passed bytearray is too short.
-        :return:
-        """
-        file_directive = cls.__empty()
-        file_directive.pdu_header = PduHeader.unpack(raw_packet=raw_packet)
-        if not check_packet_length(raw_packet_len=len(raw_packet), min_len=5):
-            raise ValueError
-        file_directive.directive_code = raw_packet[4]
-        return file_directive
-
-    def verify_file_len(self, file_size: int) -> bool:
-        if self.pdu_file_directive.pdu_header.large_file and file_size > pow(2, 64):
-            LOGGER.warning(f'File size {file_size} larger than 64 bit field')
-            raise False
-        elif not self.pdu_file_directive.pdu_header.large_file and file_size > pow(2, 32):
-            LOGGER.warning(f'File size {file_size} larger than 32 bit field')
-            raise False
-        return True
-
-    def parse_fss_field(self, raw_packet: bytearray, current_idx: int) -> (int, int):
-        """Parse the FSS field, which has different size depending on the large file flag being
-        set or not. Returns the current index incremented and the parsed file size
-        :raise ValueError: Packet not large enough
-        """
-        if self.pdu_header.large_file:
-            if not check_packet_length(len(raw_packet), current_idx + 8 + 1):
-                raise ValueError
-            file_size = struct.unpack('!I', raw_packet[current_idx: current_idx + 8])
-            current_idx += 8
-        else:
-            if not check_packet_length(len(raw_packet), current_idx + 4 + 1):
-                raise ValueError
-            file_size = struct.unpack('!I', raw_packet[current_idx: current_idx + 4])
-            current_idx += 4
-        return current_idx, file_size
diff --git a/src/tmtccmd/cfdp/pdu/finished.py b/src/tmtccmd/cfdp/pdu/finished.py
deleted file mode 100644
index 36831bc1..00000000
--- a/src/tmtccmd/cfdp/pdu/finished.py
+++ /dev/null
@@ -1,119 +0,0 @@
-from __future__ import annotations
-import enum
-
-from tmtccmd.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveCodes, Direction, \
-    TransmissionModes, CrcFlag, ConditionCode
-from tmtccmd.cfdp.definitions import LenInBytes
-from tmtccmd.cfdp.conf import check_packet_length, LOGGER
-from tmtccmd.cfdp.tlv import CfdpTlv
-from typing import List
-
-
-class DeliveryCode(enum.IntEnum):
-    DATA_COMPLETE = 0
-    DATA_INCOMPLETE = 1
-
-
-class FileDeliveryStatus(enum.IntEnum):
-    DISCARDED_DELIBERATELY = 0
-    DISCARDED_FILESTORE_REJECTION = 1
-    FILE_RETAINED = 2
-    FILE_STATUS_UNREPORTED = 3
-
-
-class FinishedPdu():
-    MINIMAL_LEN = FileDirectivePduBase.FILE_DIRECTIVE_PDU_LEN + 1
-
-    def __init__(
-            self,
-            direction: Direction,
-            delivery_code: DeliveryCode,
-            file_delivery_status: FileDeliveryStatus,
-            trans_mode: TransmissionModes,
-            condition_code: ConditionCode = ConditionCode.NO_ERROR,
-            file_store_responses: List[CfdpTlv] = [],
-            fault_location: CfdpTlv = None,
-            crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-            len_entity_id: LenInBytes = LenInBytes.NONE,
-            len_transaction_seq_num: LenInBytes = LenInBytes.NONE
-    ):
-        self.pdu_file_directive = FileDirectivePduBase(
-            directive_code=DirectiveCodes.FINISHED_PDU,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.condition_code = condition_code
-        self.delivery_code = delivery_code
-        self.file_store_responses = file_store_responses
-        self.fault_location = fault_location
-        self.file_delivery_status = file_delivery_status
-        self.might_have_fault_location = False
-        if self.condition_code != ConditionCode.NO_ERROR and \
-                self.condition_code != ConditionCode.UNSUPPORTED_CHECKSUM_TYPE:
-            self.might_have_fault_location = True
-
-    @classmethod
-    def __empty(cls) -> FinishedPdu:
-        cls(
-            direction=None,
-            delivery_code=None,
-            file_delivery_status=None,
-            trans_mode=None,
-            condition_code=None
-        )
-
-    def pack(self) -> bytearray:
-        packet = self.pdu_file_directive.pack()
-        packet[len(packet)] |= \
-            (self.condition_code << 4) | (self.delivery_code << 2) | self.file_delivery_status
-        for file_store_reponse in self.file_store_responses:
-            packet.extend(file_store_reponse.pack())
-        if self.fault_location is not None:
-            packet.extend(self.fault_location.pack())
-        return packet
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> FinishedPdu:
-        """Unpack a raw packet into a PDU object
-        :param raw_packet:
-        :raise ValueError: If packet is too short
-        :return:
-        """
-        finished_pdu = cls.__empty()
-        finished_pdu.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=raw_packet)
-        if not check_packet_length(raw_packet_len=len(raw_packet), min_len=cls.MINIMAL_LEN):
-            raise ValueError
-        current_idx = finished_pdu.pdu_file_directive.get_len()
-        first_param_byte = raw_packet[current_idx]
-        finished_pdu.condition_code = first_param_byte & 0xf0
-        finished_pdu.delivery_code = first_param_byte & 0x04
-        finished_pdu.file_delivery_status = first_param_byte & 0b11
-        current_idx += 1
-        if len(raw_packet) > current_idx:
-            finished_pdu.unpack_tlvs(raw_packet=raw_packet, start_idx=current_idx)
-        return finished_pdu
-
-    def unpack_tlvs(self, raw_packet: bytearray, start_idx: int) -> int:
-        current_idx = start_idx
-        while True:
-            current_tlv = CfdpTlv(serialize=False)
-            current_tlv.unpack(raw_bytes=raw_packet[current_idx])
-            # This will always increment at least two, so we can't get stuck in the loop
-            current_idx += current_tlv.get_total_length()
-            if current_idx > len(raw_packet) or current_idx == len(raw_packet):
-                if current_idx > len(raw_packet):
-                    LOGGER.warning(
-                        'Parser Error when parsing TLVs in Finished PDU. Possibly invalid packet'
-                    )
-                if self.might_have_fault_location:
-                    self.fault_location = current_tlv
-                else:
-                    self.file_store_responses.append(current_tlv)
-                break
-            else:
-                # Another TLV might follow, so this is a file store response
-                self.file_store_responses.append(current_tlv)
-        return current_idx
diff --git a/src/tmtccmd/cfdp/pdu/header.py b/src/tmtccmd/cfdp/pdu/header.py
deleted file mode 100644
index 920b1e0e..00000000
--- a/src/tmtccmd/cfdp/pdu/header.py
+++ /dev/null
@@ -1,147 +0,0 @@
-from __future__ import annotations
-import enum
-
-from tmtccmd.ccsds.handler import CcsdsTmHandler
-from tmtccmd.utility.logger import get_console_logger
-from tmtccmd.cfdp.definitions import LenInBytes
-from tmtccmd.cfdp.conf import get_default_length_entity_id, \
-    get_default_length_transaction_seq_num, get_default_pdu_crc_mode
-
-
-LOGGER = get_console_logger()
-
-
-class PduType(enum.IntEnum):
-    FILE_DIRECTIVE = 0
-    FILE_DATA = 1
-
-
-class Direction(enum.IntEnum):
-    TOWARDS_SENDER = 0
-    TOWARDS_RECEIVER = 1
-
-
-class TransmissionModes(enum.IntEnum):
-    ACKNOWLEDGED = 0
-    UNACKNOWLEDGED = 1
-
-
-class CrcFlag(enum.IntEnum):
-    WITH_CRC = 0
-    NO_CRC = 1
-    GLOBAL_CONFIG = 2
-
-
-class SegmentMetadataFlag(enum.IntEnum):
-    """Aways 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 p.75)"""
-    NOT_PRESENT = 0
-    PRESENT = 1
-
-
-class SegmentationControl(enum.IntEnum):
-    """Aways 0 and ignored for File Directive PDUs (CCSDS 727.0-B-5 p.75)"""
-    NO_RECORD_BOUNDARIES_PRESERVATION = 0
-    RECORD_BOUNDARIES_PRESERVATION = 1
-
-
-class PduHeader:
-    VERSION_BITS = 0b0010_0000
-
-    """This class encapsulates the fixed-format PDU header.
-    For more, information, refer to CCSDS 727.0-B-5 p.75"""
-    def __init__(
-            self,
-            pdu_type: PduType,
-            direction: Direction,
-            trans_mode: TransmissionModes,
-            crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-            len_entity_id: LenInBytes = LenInBytes.NONE,
-            len_transaction_seq_num: LenInBytes = LenInBytes.NONE,
-            seg_ctrl: SegmentationControl = SegmentationControl.NO_RECORD_BOUNDARIES_PRESERVATION,
-            segment_metadata_flag: SegmentMetadataFlag = SegmentMetadataFlag.NOT_PRESENT,
-    ):
-        """Constructor for PDU header
-        :param serialize: Specify whether a packet will be serialized or deserialized
-        :param pdu_type:
-        :param direction:
-        :param trans_mode:
-        :param crc_flag: If not supplied, assign the default configuration
-        :param len_entity_id: If not suplied, the default configuration will be used
-        :param len_transaction_seq_num: If not supplied, the default configuration will be used
-        :param seg_ctrl:
-        :param segment_metadata_flag:
-        :raise ValueError: If some field were not specified with serialize == True
-        """
-        self.pdu_type = pdu_type
-        self.direction = direction
-        self.trans_mode = trans_mode
-        self.large_file = False
-        self.pdu_data_field_length = 0
-        self.segmentation_control = seg_ctrl
-        if len_entity_id is LenInBytes.NONE:
-            self.len_entity_id = get_default_length_entity_id()
-        else:
-            self.len_entity_id = len_entity_id
-        if len_transaction_seq_num is LenInBytes.NONE:
-            self.len_transaction_seq_num = get_default_length_transaction_seq_num()
-        else:
-            self.len_transaction_seq_num = len_transaction_seq_num
-        if crc_flag == CrcFlag.GLOBAL_CONFIG:
-            self.crc_flag = get_default_pdu_crc_mode()
-        else:
-            self.crc_flag = crc_flag
-        self.segment_metadata_flag = segment_metadata_flag
-
-    def set_large_file_flag(self):
-        self.large_file = True
-
-    def set_pdu_data_field_length(self, new_length: int):
-        self.pdu_data_field_length = new_length
-
-    def pack(self) -> bytearray:
-        header = bytearray()
-        header.append(
-            self.VERSION_BITS | (self.pdu_type << 4) | (self.direction << 3) |
-            (self.trans_mode << 2) | (self.crc_flag << 1) | self.large_file
-        )
-        header.append((self.pdu_data_field_length >> 8) & 0xff)
-        header.append(self.pdu_data_field_length & 0xff)
-        header.append(
-            self.segmentation_control << 7 | self.len_entity_id << 4 |
-            self.segment_metadata_flag << 3 | self.len_transaction_seq_num
-        )
-        return header
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> PduHeader:
-        """Unpack a raw bytearray into the PDU header oject representation
-        :param raw_packet:
-        :raise ValueError: Passed bytearray is too short.
-        :return:
-        """
-        if len(raw_packet) < 4:
-            LOGGER.warning('Can not unpack less than four bytes into PDU header')
-            raise ValueError
-        pdu_type = raw_packet[0] & 0x10
-        direction = raw_packet[0] & 0x08
-        trans_mode = raw_packet[0] & 0x04
-        crc_flag = raw_packet[0] & 0x02
-        large_file = raw_packet[0] & 0x01
-        pdu_data_field_length = raw_packet[1] << 8 | raw_packet[2]
-        segmentation_control = raw_packet[3] & 0x80
-        len_entity_id = raw_packet[3] & 0x70
-        segment_metadata_flag = raw_packet[3] & 0x08
-        len_transaction_seq_num = raw_packet[3] & 0x01
-
-        return cls(
-            pdu_type=pdu_type,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            large_file=large_file,
-            pdu_data_field_length=pdu_data_field_length,
-            segmentation_control=segmentation_control,
-            len_entity_id=len_entity_id,
-            segment_metadata_flag=segment_metadata_flag,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
diff --git a/src/tmtccmd/cfdp/pdu/metadata.py b/src/tmtccmd/cfdp/pdu/metadata.py
deleted file mode 100644
index ec733859..00000000
--- a/src/tmtccmd/cfdp/pdu/metadata.py
+++ /dev/null
@@ -1,116 +0,0 @@
-from __future__ import annotations
-import struct
-from typing import List
-
-from tmtccmd.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveCodes, \
-    ConditionCode
-from tmtccmd.cfdp.pdu.header import Direction, TransmissionModes, CrcFlag
-from tmtccmd.cfdp.tlv import CfdpTlv
-from tmtccmd.cfdp.lv import CfdpLv
-from tmtccmd.cfdp.definitions import LenInBytes, ChecksumTypes
-from tmtccmd.cfdp.conf import check_packet_length
-from tmtccmd.ccsds.log import LOGGER
-
-
-class MetadataPdu():
-    def __init__(
-        self,
-        closure_requested: bool,
-        checksum_type: ChecksumTypes,
-        file_size: int,
-        source_file_name: str,
-        dest_file_name: str,
-        direction: Direction,
-        trans_mode: TransmissionModes,
-        options: List[CfdpTlv] = [],
-        crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-        len_entity_id: LenInBytes = LenInBytes.NONE,
-        len_transaction_seq_num=LenInBytes.NONE,
-    ):
-        self.pdu_file_directive = FileDirectivePduBase(
-            directive_code=DirectiveCodes.METADATA_PDU,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.closure_requested = closure_requested
-        self.checksum_type = checksum_type
-        self.file_size = file_size
-        source_file_name_as_bytes = source_file_name.encode('utf-8')
-        self.source_file_name_lv = CfdpLv(
-            value=source_file_name_as_bytes
-        )
-        dest_file_name_as_bytes = dest_file_name.encode('utf-8')
-        self.dest_file_name_lv = CfdpLv(
-            value=dest_file_name_as_bytes
-        )
-        self.options = options
-
-    @classmethod
-    def __empty(cls) -> MetadataPdu:
-        cls(
-            closure_requested=None,
-            checksum_type=None,
-            file_size=None,
-            source_file_name="",
-            dest_file_name="",
-            direction=None,
-            trans_mode=None
-        )
-
-    def pack(self):
-        if not self.pdu_file_directive.verify_file_len(self.file_size):
-            raise ValueError
-        packet = self.pdu_file_directive.pack()
-        current_idx = self.pdu_file_directive.get_len()
-        packet.append((self.closure_requested << 6) | self.checksum_type)
-        if self.pdu_file_directive.pdu_header.large_file:
-            packet.extend(struct.pack('!Q', self.file_size))
-        else:
-            packet.extend(struct.pack('!I', self.file_size))
-        packet.extend(self.source_file_name_lv.pack())
-        packet.extend(self.dest_file_name_lv.pack())
-        for option in self.options:
-            packet.extend(option.pack())
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> MetadataPdu:
-        metadata_pdu = cls.__empty()
-        metadata_pdu.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=raw_packet)
-        current_idx = metadata_pdu.pdu_file_directive.get_len()
-        # Minimal length: 1 byte + FSS (4 byte) + 2 empty LV (1 byte)
-        if not check_packet_length(len(raw_packet), metadata_pdu.pdu_file_directive.get_len() + 7):
-            raise ValueError
-        metadata_pdu.closure_requested = raw_packet[current_idx] & 0x40
-        metadata_pdu.checksum_type = raw_packet[current_idx] & 0x0f
-        current_idx += 1
-        current_idx, metadata_pdu.file_size = metadata_pdu.pdu_file_directive.parse_fss_field(
-            raw_packet=raw_packet, current_idx=current_idx
-        )
-        metadata_pdu.source_file_name_lv.unpack(raw_bytes=raw_packet[current_idx:])
-        current_idx += metadata_pdu.source_file_name_lv.get_len()
-        metadata_pdu.dest_file_name_lv.unpack(raw_bytes=raw_packet[current_idx:])
-        current_idx += metadata_pdu.dest_file_name_lv.get_len()
-        if current_idx < len(raw_packet):
-            metadata_pdu.parse_options(raw_packet=raw_packet, start_idx=current_idx)
-        return metadata_pdu
-
-    def parse_options(self, raw_packet: bytearray, start_idx: int):
-        self.options = []
-        current_idx = start_idx
-        while True:
-            current_tlv = CfdpTlv(serialize=False)
-            current_tlv.unpack(raw_bytes=raw_packet[current_idx])
-            self.options.append(current_tlv)
-            # This will always increment at least two, so we can't get stuck in the loop
-            current_idx += current_tlv.get_total_length()
-            if current_idx > len(raw_packet):
-                LOGGER.warning(
-                    'Parser Error when parsing TLVs in Finished PDU. '
-                    'Possibly invalid packet'
-                )
-                break
-            elif current_idx == len(raw_packet):
-                break
diff --git a/src/tmtccmd/cfdp/pdu/nak.py b/src/tmtccmd/cfdp/pdu/nak.py
deleted file mode 100644
index 5037ceda..00000000
--- a/src/tmtccmd/cfdp/pdu/nak.py
+++ /dev/null
@@ -1,67 +0,0 @@
-from __future__ import annotations
-import enum
-import struct
-from typing import List, Tuple
-
-from tmtccmd.cfdp.pdu.file_directive import FileDirectivePduBase, DirectiveCodes, \
-    ConditionCode
-from tmtccmd.cfdp.pdu.header import Direction, TransmissionModes, CrcFlag
-from tmtccmd.cfdp.conf import LenInBytes
-
-
-class NakPdu():
-    def __init__(
-        self,
-        direction: Direction,
-        trans_mode: TransmissionModes,
-        start_of_scope: int,
-        end_of_scope: int,
-        segment_requests: List[Tuple[int, int]],
-        crc_flag: CrcFlag = CrcFlag.GLOBAL_CONFIG,
-        len_entity_id: LenInBytes = LenInBytes.NONE,
-        len_transaction_seq_num=LenInBytes.NONE,
-    ):
-        self.pdu_file_directive = FileDirectivePduBase(
-            directive_code=DirectiveCodes.ACK_PDU,
-            direction=direction,
-            trans_mode=trans_mode,
-            crc_flag=crc_flag,
-            len_entity_id=len_entity_id,
-            len_transaction_seq_num=len_transaction_seq_num
-        )
-        self.start_of_scope = start_of_scope
-        self.end_of_scope = end_of_scope
-        self.segment_requests = segment_requests
-
-    @classmethod
-    def __empty(cls) -> NakPdu:
-        return cls(
-            direction=None,
-            trans_mode=None,
-            start_of_scope=None,
-            end_of_scope=None,
-            segment_requests=None
-        )
-
-    def pack(self) -> bytearray:
-        nak_pdu = self.pdu_file_directive.pack()
-        if not self.pdu_file_directive.pdu_header.large_file:
-            nak_pdu.extend(struct.pack('!I', self.start_of_scope))
-            nak_pdu.extend(struct.pack('!I', self.end_of_scope))
-        else:
-            nak_pdu.extend(struct.pack('!Q', self.start_of_scope))
-            nak_pdu.extend(struct.pack('!Q', self.end_of_scope))
-        for segment_request in self.segment_requests:
-            if not self.pdu_file_directive.pdu_header.large_file:
-                nak_pdu.extend(struct.pack('!I', segment_request[0]))
-                nak_pdu.extend(struct.pack('!I', segment_request[1]))
-            else:
-                nak_pdu.extend(struct.pack('!Q', segment_request[0]))
-                nak_pdu.extend(struct.pack('!Q', segment_request[1]))
-
-    @classmethod
-    def unpack(cls, raw_packet: bytearray) -> NakPdu:
-        nak_pdu = cls.__empty()
-        nak_pdu.pdu_file_directive = FileDirectivePduBase.unpack(raw_packet=raw_packet)
-        current_idx = nak_pdu.pdu_file_directive.get_len()
-        # TODO: Implement
diff --git a/src/tmtccmd/cfdp/tlv.py b/src/tmtccmd/cfdp/tlv.py
deleted file mode 100644
index 501978c8..00000000
--- a/src/tmtccmd/cfdp/tlv.py
+++ /dev/null
@@ -1,78 +0,0 @@
-from __future__ import annotations
-import enum
-from tmtccmd.ccsds.log import LOGGER
-
-
-class TlvTypes(enum.IntEnum):
-    FILESTORE_REQUEST = 0x00
-    FILESTORE_RESPONSE = 0x01
-    MESSAGE_TO_USER = 0x02
-    FAULT_HANDLER = 0x04
-    FLOW_LABEL = 0x05
-    ENTITY_ID = 0x06
-
-
-class CfdpTlv:
-    MINIMAL_LEN = 2
-
-    """Encapsulates the CFDP TLV (type-lenght-value) format.
-    For more information, refer to CCSDS 727.0-B-5 p.77
-    """
-    def __init__(
-            self,
-            type: TlvTypes,
-            length: int,
-            value: bytearray
-    ):
-        """Constructor for TLV field.
-        :param serialize: Specfiy whether a packet is serialized or deserialized. For serialize,
-        all input parameter have to be valid. For deserialization, the parameter do not have
-        to be specified
-        :param type:
-        :param length:
-        :param value:
-        :raise ValueError: Length invalid or value length not equal to specified length
-        """
-        if length > 255 or length < 0:
-            raise ValueError
-        if len(value) != length:
-            raise ValueError
-        self.type = type
-        self.length = length
-        self.value = value
-
-    def pack(self) -> bytearray:
-        tlv_data = bytearray()
-        tlv_data.append(self.type)
-        tlv_data.append(self.length)
-        tlv_data.extend(self.value)
-        return tlv_data
-
-    @classmethod
-    def unpack(cls, raw_bytes: bytearray) -> CfdpTlv:
-        """Parses LV field at the start of the given bytearray
-        :param raw_bytes:
-        :raise ValueError: Invalid format of the raw bytearray or type field invalid
-        :return:
-        """
-        if len(raw_bytes) < 2:
-            LOGGER.warning('Invalid length for TLV field, less than 2')
-            raise ValueError
-        try:
-            type = TlvTypes(raw_bytes[0])
-        except ValueError:
-            LOGGER.warning(
-                f'TLV field invalid, found value {type} is not a possible TLV parameter'
-            )
-            raise ValueError
-        value = bytearray()
-        if len(raw_bytes) > 2:
-            value.extend(raw_bytes[2:])
-        return cls(
-            type=raw_bytes[0],
-            length=raw_bytes[1],
-            value=value
-        )
-
-    def get_total_length(self) -> int:
-        return self.MINIMAL_LEN + len(self.value)
diff --git a/src/tmtccmd/com_if/dummy_com_if.py b/src/tmtccmd/com_if/dummy_com_if.py
index b8ec920b..9446fb9e 100644
--- a/src/tmtccmd/com_if/dummy_com_if.py
+++ b/src/tmtccmd/com_if/dummy_com_if.py
@@ -1,7 +1,7 @@
 """Dummy Communication Interface. Currently serves to provide an example without external hardware
 """
 from tmtccmd.com_if.com_interface_base import CommunicationInterface
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 from tmtccmd.tm import TelemetryListT, Service1TM, Service17TM
 from tmtccmd.pus.service_17_test import Srv17Subservices
 from tmtccmd.utility.logger import get_console_logger
diff --git a/src/tmtccmd/com_if/qemu_com_if.py b/src/tmtccmd/com_if/qemu_com_if.py
index a50d1821..fb90f03e 100644
--- a/src/tmtccmd/com_if/qemu_com_if.py
+++ b/src/tmtccmd/com_if/qemu_com_if.py
@@ -193,7 +193,7 @@ def data_available_fixed_frame(self, timeout: float = 0) -> int:
             return self.usart.get_data_in_waiting()
         return 0
 
-    def data_availanle_dle(self, timeout: float = 0) -> int:
+    def data_available_dle(self, timeout: float = 0) -> int:
         elapsed_time = 0
         start_time = time.time()
         sleep_time = timeout / 3.0
@@ -533,7 +533,7 @@ async def read_until_async(self, expected, size=None, timeout=None):
         finally:
             end = self.datab.find(expected)
             if end == -1:
-                end = self.datab.len()
+                end = len(self.datab)
             else:
                 end += len(expected)
 
diff --git a/src/tmtccmd/com_if/tcpip_tcp_com_if.py b/src/tmtccmd/com_if/tcpip_tcp_com_if.py
index 07097891..71d7b744 100644
--- a/src/tmtccmd/com_if/tcpip_tcp_com_if.py
+++ b/src/tmtccmd/com_if/tcpip_tcp_com_if.py
@@ -10,7 +10,9 @@
 import threading
 import select
 from collections import deque
-from typing import Union
+from typing import Union, Optional
+
+from spacepackets.ccsds.spacepacket import parse_space_packets
 
 from tmtccmd.utility.logger import get_console_logger
 from tmtccmd.config.definitions import CoreModeList
@@ -19,7 +21,6 @@
 from tmtccmd.utility.tmtc_printer import TmTcPrinter
 from tmtccmd.config.definitions import EthernetAddressT
 from tmtccmd.utility.conf_util import acquire_timeout
-from tmtccmd.ccsds.spacepacket import parse_space_packets
 
 LOGGER = get_console_logger()
 
@@ -38,7 +39,7 @@ class TcpCommunicationType(enum.Enum):
 class TcpIpTcpComIF(CommunicationInterface):
     """Communication interface for TCP communication."""
     DEFAULT_LOCK_TIMEOUT = 0.4
-    RECV_TIMEOUT = 0.2
+    TM_LOOP_DELAY = 0.2
 
     def __init__(
             self, com_if_key: str, com_type: TcpCommunicationType, space_packet_id: int,
@@ -68,6 +69,7 @@ def __init__(
         self.max_packets_stored = max_packets_stored
         self.init_mode = init_mode
 
+        self.__tcp_socket: Optional[socket.socket] = None
         self.__last_connection_time = 0
         self.__tm_thread_kill_signal = threading.Event()
         # Separate thread to request TM packets periodically if no TCs are being sent
@@ -75,7 +77,7 @@ def __init__(
         self.__tm_queue = deque()
         self.__analysis_queue = deque()
         # Only allow one connection to OBSW at a time for now by using this lock
-        self.__socket_lock = threading.Lock()
+        # self.__socket_lock = threading.Lock()
         self.__queue_lock = threading.Lock()
 
     def __del__(self):
@@ -86,27 +88,25 @@ def __del__(self):
 
     def initialize(self, args: any = None) -> any:
         self.__tm_thread_kill_signal.clear()
+        self.__tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+        self.__tcp_socket.connect(self.send_address)
 
     def open(self, args: any = None):
         self.__tcp_conn_thread.start()
 
     def close(self, args: any = None) -> None:
         self.__tm_thread_kill_signal.set()
-        self.__tcp_conn_thread.join(self.tm_polling_frequency)
+        if self.__tcp_conn_thread.is_alive():
+            self.__tcp_conn_thread.join(self.tm_polling_frequency)
+        try:
+            self.__tcp_socket.shutdown(socket.SHUT_RDWR)
+        except OSError:
+            LOGGER.warning("TCP socket endpoint was already closed or not connected")
+        self.__tcp_socket.close()
 
     def send(self, data: bytearray):
         try:
-            with acquire_timeout(self.__socket_lock, timeout=self.DEFAULT_LOCK_TIMEOUT) as \
-                    acquired:
-                if not acquired:
-                    LOGGER.warning("Acquiring socket lock failed!")
-                tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                tcp_socket.connect(self.send_address)
-                tcp_socket.sendto(data, self.send_address)
-                tcp_socket.shutdown(socket.SHUT_WR)
-                self.__receive_tm_packets(tcp_socket)
-                self.__last_connection_time = time.time()
-                tcp_socket.close()
+            self.__tcp_socket.sendto(data, self.send_address)
         except ConnectionRefusedError:
             LOGGER.warning("TCP connection attempt failed..")
 
@@ -132,48 +132,30 @@ def receive(self, poll_timeout: float = 0) -> TelemetryListT:
 
     def __tcp_tm_client(self):
         while True and not self.__tm_thread_kill_signal.is_set():
-            if time.time() - self.__last_connection_time >= self.tm_polling_frequency:
-                try:
-                    with acquire_timeout(self.__socket_lock, timeout=self.DEFAULT_LOCK_TIMEOUT) as \
-                            acquired:
-                        if not acquired:
-                            LOGGER.warning("Acquiring socket lock in periodic handler failed!")
-                        tcp_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-                        tcp_socket.connect(self.send_address)
-                        tcp_socket.shutdown(socket.SHUT_WR)
-                        self.__receive_tm_packets(tcp_socket=tcp_socket)
-                        self.__last_connection_time = time.time()
-                except ConnectionRefusedError:
-                    LOGGER.warning("TCP connection attempt failed..")
-                    self.__last_connection_time = time.time()
-            time.sleep(self.tm_polling_frequency / 2.0)
-
-    def __receive_tm_packets(self, tcp_socket: socket.socket):
-        while True:
             try:
-                ready = select.select([tcp_socket], [], [], self.RECV_TIMEOUT)
-                if ready[0]:
-                    bytes_recvd = tcp_socket.recv(self.max_recv_size)
-                else:
-                    LOGGER.warning(
-                        'TCP reception timeout. Server side might not shut down connection!'
-                    )
-                    break
-                if len(bytes_recvd) > 0:
-                    with acquire_timeout(self.__queue_lock, timeout=self.DEFAULT_LOCK_TIMEOUT) as \
-                            acquired:
-                        if not acquired:
-                            LOGGER.warning("Acquiring queue lock failed!")
-                        if self.__tm_queue.__len__() >= self.max_packets_stored:
-                            LOGGER.warning(
-                                "Number of packets in TCP queue too large. Overwriting old packets.."
-                            )
-                            self.__tm_queue.pop()
-                        self.__tm_queue.appendleft(bytearray(bytes_recvd))
-                elif bytes_recvd is None or len(bytes_recvd) == 0:
-                    break
-            except ConnectionResetError:
-                LOGGER.exception('ConnectionResetError. TCP server might not be up')
+                self.__receive_tm_packets()
+            except ConnectionRefusedError:
+                LOGGER.warning("TCP connection attempt failed..")
+            time.sleep(self.TM_LOOP_DELAY)
+
+    def __receive_tm_packets(self):
+        try:
+            ready = select.select([self.__tcp_socket], [], [], 0)
+            if ready[0]:
+                bytes_recvd = self.__tcp_socket.recv(self.max_recv_size)
+                with acquire_timeout(self.__queue_lock, timeout=self.DEFAULT_LOCK_TIMEOUT) as \
+                        acquired:
+                    if not acquired:
+                        LOGGER.warning("Acquiring queue lock failed!")
+                    if self.__tm_queue.__len__() >= self.max_packets_stored:
+                        LOGGER.warning(
+                            "Number of packets in TCP queue too large. "
+                            "Overwriting old packets.."
+                        )
+                        self.__tm_queue.pop()
+                    self.__tm_queue.appendleft(bytearray(bytes_recvd))
+        except ConnectionResetError:
+            LOGGER.exception('ConnectionResetError. TCP server might not be up')
 
     def data_available(self, timeout: float = 0, parameters: any = 0) -> bool:
         if self.__tm_queue:
diff --git a/src/tmtccmd/com_if/tcpip_udp_com_if.py b/src/tmtccmd/com_if/tcpip_udp_com_if.py
index fff2751f..a67bc93a 100644
--- a/src/tmtccmd/com_if/tcpip_udp_com_if.py
+++ b/src/tmtccmd/com_if/tcpip_udp_com_if.py
@@ -26,9 +26,12 @@
 class TcpIpUdpComIF(CommunicationInterface):
     """Communication interface for UDP communication."""
     def __init__(
-            self, com_if_key: str, tm_timeout: float, tc_timeout_factor: float, send_address: EthernetAddressT,
-            max_recv_size: int, recv_addr: Union[None, EthernetAddressT] = None,
-            tmtc_printer: Union[None, TmTcPrinter] = None, init_mode: int = CoreModeList.LISTENER_MODE):
+            self, com_if_key: str, tm_timeout: float, tc_timeout_factor: float,
+            send_address: EthernetAddressT, max_recv_size: int,
+            recv_addr: Union[None, EthernetAddressT] = None,
+            tmtc_printer: Union[None, TmTcPrinter] = None,
+            init_mode: int = CoreModeList.LISTENER_MODE
+    ):
         """Initialize a communication interface to send and receive UDP datagrams.
         :param tm_timeout:
         :param tc_timeout_factor:
diff --git a/src/tmtccmd/config/args.py b/src/tmtccmd/config/args.py
index c809a8b1..bb5ef3e7 100644
--- a/src/tmtccmd/config/args.py
+++ b/src/tmtccmd/config/args.py
@@ -127,7 +127,8 @@ def add_default_mode_arguments(arg_parser: argparse.ArgumentParser):
         f"GUI mode\n"
     help_text += seq_help + listener_help + gui_help
     arg_parser.add_argument(
-        '-m', '--mode', type=str, help=help_text, default="seqcmd"
+        '-m', '--mode', type=str, help=help_text,
+        default=CoreModeStrings[CoreModeList.SEQUENTIAL_CMD_MODE]
     )
 
 
@@ -181,16 +182,17 @@ def handle_unspecified_args(args) -> None:
     :return: None
     """
     from tmtccmd.config.hook import get_global_hook_obj
+    from tmtccmd.config.definitions import CoreModeStrings
     if args.tm_timeout is None:
         args.tm_timeout = 5.0
     if args.mode is None:
-        args.mode = CoreModeList.SEQUENTIAL_CMD_MODE
+        args.mode = CoreModeStrings[CoreModeList.SEQUENTIAL_CMD_MODE]
     service_op_code_dict = dict()
     if args.service is None or args.op_code is None:
         hook_obj = get_global_hook_obj()
         service_op_code_dict = hook_obj.get_service_op_code_dictionary()
     if args.service is None:
-        if args.mode == CoreModeList.SEQUENTIAL_CMD_MODE:
+        if args.mode == CoreModeStrings[CoreModeList.SEQUENTIAL_CMD_MODE]:
             LOGGER.info("No service argument (-s) specified, prompting from user..")
             # Try to get the service list from the hook base and prompt service from user
             args.service = prompt_service(service_op_code_dict)
@@ -214,7 +216,7 @@ def handle_empty_args(args) -> None:
 
 
 def prompt_service(service_op_code_dict: ServiceOpCodeDictT) -> str:
-    service_adjustment = 10
+    service_adjustment = 20
     info_adjustment = 30
     horiz_line_num = service_adjustment + info_adjustment + 3
     horiz_line = horiz_line_num * "-"
diff --git a/src/tmtccmd/config/com_if.py b/src/tmtccmd/config/com_if.py
index 0b90784e..ff69db19 100644
--- a/src/tmtccmd/config/com_if.py
+++ b/src/tmtccmd/config/com_if.py
@@ -24,6 +24,8 @@ def create_communication_interface_default(
     :param com_if_key:
     :param tmtc_printer:
     :param json_cfg_path:
+    TODO: List of packet IDs?
+    :param space_packet_id: Can be used by communication interfaces as a start marker (e.g. TCP)
     :return:
     """
     from tmtccmd.com_if.dummy_com_if import DummyComIF
diff --git a/src/tmtccmd/config/definitions.py b/src/tmtccmd/config/definitions.py
index 6e8f11d4..b1a58963 100644
--- a/src/tmtccmd/config/definitions.py
+++ b/src/tmtccmd/config/definitions.py
@@ -1,5 +1,4 @@
-"""
-@brief  Definitions for the TMTC commander core
+"""Definitions for the TMTC commander core
 """
 import enum
 from typing import Tuple, Dict, Optional
diff --git a/src/tmtccmd/config/globals.py b/src/tmtccmd/config/globals.py
index 1f49523a..6fbe7ca6 100644
--- a/src/tmtccmd/config/globals.py
+++ b/src/tmtccmd/config/globals.py
@@ -5,7 +5,7 @@
 
 from tmtccmd.utility.logger import get_console_logger
 from tmtccmd.utility.conf_util import check_args_in_dict, print_core_globals
-from tmtccmd.ecss.conf import PusVersion, set_default_apid, get_default_apid, \
+from spacepackets.ecss.conf import PusVersion, set_default_apid, get_default_apid, \
     set_pus_tc_version, set_pus_tm_version
 from tmtccmd.core.globals_manager import update_global, get_global
 from tmtccmd.config.definitions import CoreGlobalIds, CoreModeList, CoreServiceList, \
@@ -148,6 +148,7 @@ def handle_mode_arg(
         mode_arg=mode_param, custom_modes_list=custom_modes_list
     )
     update_global(CoreGlobalIds.MODE, mode_param)
+    return mode_param
 
 
 def handle_com_if_arg(
@@ -260,8 +261,10 @@ def check_and_set_core_service_arg(
         service_arg_invalid = True
 
     if service_arg_invalid:
-        LOGGER.warning(f"Passed service argument might be invalid, "
-                       f"setting to {CoreServiceList.SERVICE_17}")
+        LOGGER.warning(
+            f"Passed service argument might be invalid, "
+            f"setting to {CoreServiceList.SERVICE_17}"
+        )
         service_value = CoreServiceList.SERVICE_17
     update_global(CoreGlobalIds.CURRENT_SERVICE, service_value)
 
diff --git a/src/tmtccmd/ecss/__init__.py b/src/tmtccmd/ecss/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/tmtccmd/ecss/conf.py b/src/tmtccmd/ecss/conf.py
deleted file mode 100644
index b78d611f..00000000
--- a/src/tmtccmd/ecss/conf.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import enum
-
-
-class PusVersion(enum.IntEnum):
-    PUS_A = 0,
-    PUS_C = 1,
-    UNKNOWN = 99
-
-
-class EcssConfKeys(enum.IntEnum):
-    ECSS_APID = 0,
-    PUS_TM_TYPE = 1,
-    PUS_TC_TYPE = 2,
-    ECSS_TM_APID = 3
-
-
-ECSS_DICT = {
-    EcssConfKeys.ECSS_APID: 0xef,
-    EcssConfKeys.PUS_TM_TYPE: PusVersion.PUS_C,
-    EcssConfKeys.PUS_TC_TYPE: PusVersion.PUS_C,
-    EcssConfKeys.ECSS_TM_APID: 0xef
-}
-
-
-def set_default_apid(default_apid: int):
-    ECSS_DICT[EcssConfKeys.ECSS_APID] = default_apid
-
-
-def get_default_apid() -> int:
-    return ECSS_DICT[EcssConfKeys.ECSS_APID]
-
-
-def set_pus_tc_version(pus_type: PusVersion):
-    ECSS_DICT[EcssConfKeys.PUS_TC_TYPE] = pus_type
-
-
-def get_pus_tc_version() -> PusVersion:
-    return ECSS_DICT[EcssConfKeys.PUS_TC_TYPE]
-
-
-def set_pus_tm_version(pus_type: PusVersion):
-    ECSS_DICT[EcssConfKeys.PUS_TM_TYPE] = pus_type
-
-
-def get_pus_tm_version() -> PusVersion:
-    return ECSS_DICT[EcssConfKeys.PUS_TM_TYPE]
-
-
-def insert_tm_apid(tm_apid: int):
-    ECSS_DICT[EcssConfKeys.ECSS_TM_APID] = tm_apid
-
-
-def get_tm_apid() -> int:
-    return ECSS_DICT[EcssConfKeys.ECSS_TM_APID]
diff --git a/src/tmtccmd/ecss/tc.py b/src/tmtccmd/ecss/tc.py
deleted file mode 100644
index 805d8fdc..00000000
--- a/src/tmtccmd/ecss/tc.py
+++ /dev/null
@@ -1,268 +0,0 @@
-"""This module contains the PUS telecommand class representation to pack telecommands.
-"""
-from __future__ import annotations
-import sys
-from typing import Tuple
-
-from tmtccmd.ccsds.log import LOGGER
-from tmtccmd.ccsds.spacepacket import \
-    SpacePacketHeader, \
-    PacketTypes, \
-    SPACE_PACKET_HEADER_SIZE
-from tmtccmd.ecss.conf import get_default_apid, PusVersion, get_pus_tc_version
-
-
-try:
-    import crcmod
-except ImportError:
-    print("crcmod package not installed!")
-    sys.exit(1)
-
-
-class PusTcDataFieldHeaderSerialize:
-    def __init__(
-            self, service_type: int, service_subtype: int, source_id: int = 0,
-            pus_tc_version: PusVersion = PusVersion.PUS_C, ack_flags: int = 0b1111,
-            secondary_header_flag: int = 0
-    ):
-        self.service_type = service_type
-        self.service_subtype = service_subtype
-        self.source_id = source_id
-        self.pus_tc_version = pus_tc_version
-        self.ack_flags = ack_flags
-        if self.pus_tc_version == PusVersion.PUS_A:
-            pus_version_num = 1
-            self.pus_version_and_ack_byte = \
-                secondary_header_flag << 7 | pus_version_num << 4 | ack_flags
-        else:
-            pus_version_num = 2
-            self.pus_version_and_ack_byte = pus_version_num << 4 | ack_flags
-
-    def pack(self) -> bytearray:
-        header_raw = bytearray()
-        header_raw.append(self.pus_version_and_ack_byte)
-        header_raw.append(self.service_type)
-        header_raw.append(self.service_subtype)
-        if self.pus_tc_version == PusVersion.PUS_C:
-            header_raw.append(self.source_id << 8 & 0xff)
-            header_raw.append(self.source_id & 0xff)
-        else:
-            # PUS A includes optional source ID field as well
-            header_raw.append(self.source_id)
-        return header_raw
-
-    def get_header_size(self):
-        if self.pus_tc_version == PusVersion.PUS_A:
-            return 4
-        elif self.pus_tc_version == PusVersion.PUS_C:
-            return 5
-
-
-# pylint: disable=too-many-instance-attributes
-# pylint: disable=too-many-arguments
-class PusTelecommand:
-    """Class representation of a PUS telecommand. It can be used to pack a raw telecommand from
-    input parameters. The structure of a PUS telecommand is specified in ECSS-E-70-41A on p.42
-    and is also shown below (bottom)
-    """
-    # This is the current size of a telecommand without application data. Consists of
-    # the 6 byte packet header, 4 byte data field header (1 byte source ID) and 2 byte CRC.
-    CURRENT_NON_APP_DATA_SIZE = 10
-
-    def __init__(
-            self, service: int, subservice: int, ssc=0,
-            app_data: bytearray = bytearray([]), source_id: int = 0,
-            pus_tc_version: int = PusVersion.UNKNOWN, ack_flags: int = 0b1111, apid: int = -1
-    ):
-        """Initiate a PUS telecommand from the given parameters. The raw byte representation
-        can then be retrieved with the pack() function.
-
-        :param service: PUS service number
-        :param subservice: PUS subservice number
-        :param apid: Application Process ID as specified by CCSDS
-        :param ssc: Source Sequence Count. Application should take care of incrementing this.
-            Limited to 2 to the power of 14 by the number of bits in the header
-        :param app_data: Application data in the Packet Data Field
-        :param source_id: Source ID will be supplied as well. Can be used to distinguish
-            different packet sources (e.g. different ground stations)
-        :param pus_tc_version:  PUS TC version. 1 for ECSS-E-70-41A
-
-        """
-        if apid == -1:
-            apid = get_default_apid()
-        self.apid = apid
-        if pus_tc_version == PusVersion.UNKNOWN:
-            pus_tc_version = get_pus_tc_version()
-        packet_type = PacketTypes.PACKET_TYPE_TC
-        secondary_header_flag = 1
-        if subservice > 255:
-            LOGGER.warning("Subservice value invalid. Setting to 0")
-            subservice = 0
-        if service > 255:
-            LOGGER.warning("Service value invalid. Setting to 0")
-            service = 0
-        # SSC can have maximum of 14 bits
-        if ssc > pow(2, 14):
-            LOGGER.warning("SSC invalid, setting to 0")
-            ssc = 0
-        self._data_field_header = PusTcDataFieldHeaderSerialize(
-            service_type=service, service_subtype=subservice, ack_flags=ack_flags,
-            source_id=source_id, pus_tc_version=pus_tc_version
-        )
-        data_length = self.get_data_length(
-            secondary_header_len=self._data_field_header.get_header_size(),
-            app_data_len=len(app_data),
-        )
-        self._space_packet_header = SpacePacketHeader(
-            apid=apid, secondary_header_flag=secondary_header_flag, packet_type=packet_type,
-            data_length=data_length, source_sequence_count=ssc
-        )
-        self.app_data = app_data
-        self.packed_data = bytearray()
-
-    def __repr__(self):
-        """Returns the representation of a class instance."""
-        return f"{self.__class__.__name__}(service={self._data_field_header.service_type!r}, " \
-               f"subservice={self._data_field_header.service_subtype!r}, " \
-               f"ssc={self._space_packet_header.ssc!r}, apid={self.apid})"
-
-    def __str__(self):
-        """Returns string representation of a class instance."""
-        return f"TC[{self._data_field_header.service_type}, " \
-               f"{self._data_field_header.service_subtype}] with SSC {self._space_packet_header.ssc}"
-
-    def get_total_length(self):
-        """Length of full packet in bytes.
-        The header length is 6 bytes and the data length + 1 is the size of the data field.
-        """
-        return self.get_data_length(
-            secondary_header_len=self._data_field_header.get_header_size(),
-            app_data_len=len(self.app_data)
-        ) + SPACE_PACKET_HEADER_SIZE + 1
-
-    def pack(self) -> bytearray:
-        """Serializes the TC data fields into a bytearray."""
-        self.packed_data = bytearray()
-        self.packed_data.extend(self._space_packet_header.pack())
-        self.packed_data.extend(self._data_field_header.pack())
-        self.packed_data += self.app_data
-        crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-        crc = crc_func(self.packed_data)
-
-        self.packed_data.append((crc & 0xFF00) >> 8)
-        self.packed_data.append(crc & 0xFF)
-        return self.packed_data
-
-    @staticmethod
-    def get_data_length(app_data_len: int, secondary_header_len: int) -> int:
-        """Retrieve size of TC packet in bytes.
-        Formula according to PUS Standard: C = (Number of octets in packet data field) - 1.
-        The size of the TC packet is the size of the packet secondary header with
-        source ID + the length of the application data + length of the CRC16 checksum - 1
-        """
-        try:
-            data_length = secondary_header_len + app_data_len + 1
-            return data_length
-        except TypeError:
-            LOGGER.warning("PusTelecommand: Invalid type of application data!")
-            return 0
-
-    def pack_command_tuple(self) -> Tuple[bytearray, PusTelecommand]:
-        """Pack a tuple consisting of the raw packet as the first entry and the class representation
-        as the second entry
-        """
-        command_tuple = (self.pack(), self)
-        return command_tuple
-
-    def get_service(self):
-        return self._data_field_header.service_type
-
-    def get_subservice(self):
-        return self._data_field_header.service_subtype
-
-    def get_ssc(self):
-        return self._space_packet_header.ssc
-
-    def get_apid(self):
-        return self._space_packet_header.apid
-
-    def get_packet_id(self):
-        return self._space_packet_header.packet_id
-
-    def get_app_data(self):
-        return self.app_data
-
-    def print(self):
-        """Print the raw command in a clean format.
-        """
-        packet = self.pack()
-        print("Command in Hexadecimal: [", end="")
-        for counter in range(len(packet)):
-            if counter == len(packet) - 1:
-                print(str(hex(packet[counter])), end="")
-            else:
-                print(str(hex(packet[counter])) + ", ", end="")
-        print("]")
-
-
-def generate_packet_crc(tc_packet: bytearray) -> bytearray:
-    """Removes current Packet Error Control, calculates new
-    CRC16 checksum and adds it as correct Packet Error Control Code.
-    Reference: ECSS-E70-41A p. 207-212
-    """
-    crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-    crc = crc_func(bytearray(tc_packet[0:len(tc_packet) - 2]))
-    tc_packet[len(tc_packet) - 2] = (crc & 0xFF00) >> 8
-    tc_packet[len(tc_packet) - 1] = crc & 0xFF
-    return tc_packet
-
-
-def generate_crc(data: bytearray) -> bytearray:
-    """Takes the application data, appends the CRC16 checksum and returns resulting bytearray
-    """
-    data_with_crc = bytearray()
-    data_with_crc += data
-    crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-    crc = crc_func(data)
-    data_with_crc.append((crc & 0xFF00) >> 8)
-    data_with_crc.append(crc & 0xFF)
-    return data_with_crc
-
-
-# pylint: disable=line-too-long
-
-# Structure of a PUS TC Packet :
-# A PUS wiretapping_packet consists of consecutive bits, the allocation and structure is standardised.
-# Extended information can be found in ECSS-E-70-41A  on p.42
-# The easiest form to send a PUS Packet is in hexadecimal form.
-# A two digit hexadecimal number equals one byte, 8 bits or one octet
-# o = optional, Srv = Service
-#
-# The structure is shown as follows for TC[17,1]
-# 1. Structure Header
-# 2. Structure Subheader
-# 3. Component (size in bits)
-# 4. Hexadecimal number
-# 5. Binary Number
-# 6. Decimal Number
-#
-# -------------------------------------------Packet Header(48)------------------------------------------|   Packet   |
-#  ----------------Packet ID(16)----------------------|Packet Sequence Control (16)| Packet Length (16) | Data Field |
-# Version       | Type(1) |Data Field    |APID(11)    | SequenceFlags(2) |Sequence |                    | (Variable) |
-# Number(3)     |         |Header Flag(1)|            |                  |Count(14)|                    |            |
-#           0x18               |    0x73              |       0xc0       | 0x19    |   0x00  |   0x04   |            |
-#    000      1      1      000|  01110011            | 11  000000       | 00011001|00000000 | 0000100  |            |
-#     0   |   1   |  1     |    115(ASCII s)          | 3 |            25          |   0     |    4     |            |
-#
-#   - Packet Length is an unsigned integer C = Number of Octets in Packet Data Field - 1
-#
-# Packet Data Field Structure:
-#
-# ------------------------------------------------Packet Data Field------------------------------------------------- |
-# ---------------------------------Data Field Header ---------------------------|AppData|Spare|    PacketErrCtr      |
-# CCSDS(1)|TC PUS Ver.(3)|Ack(4)|SrvType (8)|SrvSubtype(8)|Source ID(o)|Spare(o)|  (var)|(var)|         (16)         |
-#        0x11 (0x1F)            |  0x11     |   0x01      |            |        |       |     | 0xA0     |    0xB8   |
-#    0     001     1111         |00010001   | 00000001    |            |        |       |     |          |           |
-#    0      1       1111        |    17     |     1       |            |        |       |     |          |           |
-#
-#   - The source ID is present as one byte. For now, ground = 0x00.
diff --git a/src/tmtccmd/ecss/tm.py b/src/tmtccmd/ecss/tm.py
deleted file mode 100644
index e722c0f4..00000000
--- a/src/tmtccmd/ecss/tm.py
+++ /dev/null
@@ -1,568 +0,0 @@
-from __future__ import annotations
-from abc import abstractmethod
-
-from crcmod import crcmod
-
-from tmtccmd.ccsds.log import LOGGER
-from tmtccmd.ccsds.spacepacket import SpacePacketHeader, SPACE_PACKET_HEADER_SIZE, \
-    get_total_space_packet_len_from_len_field, PacketTypes
-from tmtccmd.ccsds.time import CdsShortTimestamp, read_p_field
-from tmtccmd.ecss.conf import get_pus_tm_version, PusVersion, get_tm_apid
-from tmtccmd.tm.base import PusTmInfoInterface, PusTmInterface
-
-
-def get_service_from_raw_pus_packet(raw_bytearray: bytearray) -> int:
-    """Determine the service ID from a raw packet, which can be used for packet deserialization.
-
-    It is assumed that the user already checked that the raw bytearray contains a PUS packet and
-    only basic sanity checks will be performed.
-    :raise ValueError: If raw bytearray is too short
-    """
-    if len(raw_bytearray) < 8:
-        raise ValueError
-    return raw_bytearray[7]
-
-
-class PusTelemetry:
-    """Generic PUS telemetry class representation.
-    It is instantiated by passing the raw pus telemetry packet (bytearray) to the constructor.
-    It automatically deserializes the packet, exposing various packet fields via getter functions.
-    PUS Telemetry structure according to ECSS-E-70-41A p.46. Also see structure below (bottom).
-    """
-    CDS_SHORT_SIZE = 7
-    PUS_TIMESTAMP_SIZE = CDS_SHORT_SIZE
-
-    def __init__(
-            self, service_id: int, subservice_id: int, time: CdsShortTimestamp = None, ssc: int = 0,
-            source_data: bytearray = bytearray([]), apid: int = -1, message_counter: int = 0,
-            space_time_ref: int = 0b0000, destination_id: int = 0,
-            packet_version: int = 0b000, pus_version: PusVersion = PusVersion.UNKNOWN,
-            pus_tm_version: int = 0b0001, ack: int = 0b1111, secondary_header_flag: bool = True,
-    ):
-        if apid == -1:
-            apid = get_tm_apid()
-        if pus_version == PusVersion.UNKNOWN:
-            pus_version = get_pus_tm_version()
-        if time is None:
-            time = CdsShortTimestamp.init_from_current_time()
-        # packet type for telemetry is 0 as specified in standard
-        # specified in standard
-        packet_type = PacketTypes.PACKET_TYPE_TM
-        self._source_data = source_data
-        data_length = self.get_source_data_length(
-            timestamp_len=PusTelemetry.PUS_TIMESTAMP_SIZE, pus_version=pus_version
-        )
-        self.space_packet_header = SpacePacketHeader(
-            apid=apid, packet_type=packet_type, secondary_header_flag=secondary_header_flag,
-            packet_version=packet_version, data_length=data_length, source_sequence_count=ssc
-        )
-        self.secondary_packet_header = PusTmSecondaryHeader(
-            pus_version=pus_version, service_id=service_id, subservice_id=subservice_id,
-            message_counter=message_counter, destination_id=destination_id,
-            spacecraft_time_ref=space_time_ref, time=time
-        )
-        self._valid = False
-        self.print_info = ''
-
-    @classmethod
-    def __empty(cls, pus_version: PusVersion = PusVersion.UNKNOWN) -> PusTelemetry:
-        return PusTelemetry(
-            service_id=0, subservice_id=0, time=CdsShortTimestamp.init_from_current_time()
-        )
-
-    def pack(self) -> bytearray:
-        """
-        Serializes the PUS telemetry into a raw packet.
-        """
-        tm_packet_raw = bytearray()
-        # PUS Header
-        tm_packet_raw.extend(self.space_packet_header.pack())
-        # PUS Source Data Field
-        tm_packet_raw.extend(self.secondary_packet_header.pack())
-        # Source Data
-        tm_packet_raw.extend(self._source_data)
-        # CRC16 checksum
-        crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xffff, xorOut=0x0000)
-        crc16 = crc_func(tm_packet_raw)
-        tm_packet_raw.append((crc16 & 0xff00) >> 8)
-        tm_packet_raw.append(crc16 & 0xff)
-        return tm_packet_raw
-
-    @classmethod
-    def unpack(
-            cls, raw_telemetry: bytearray, pus_version: PusVersion = PusVersion.UNKNOWN
-    ) -> PusTelemetry:
-        """Attempts to construct a generic PusTelemetry class given a raw bytearray.
-        :raises ValueError: if the format of the raw bytearray is invalid, for example the length
-        :param raw_telemetry:
-        """
-        if raw_telemetry is None or len(raw_telemetry) == 0:
-            if raw_telemetry is None:
-                LOGGER.warning("Given byte stream invalid!")
-            elif len(raw_telemetry) == 0:
-                LOGGER.warning("Given byte stream empty!")
-            raise ValueError
-        pus_tm = cls.__empty(pus_version=pus_version)
-        pus_tm.space_packet_header = SpacePacketHeader.unpack(space_packet_raw=raw_telemetry)
-        expected_packet_len = get_total_space_packet_len_from_len_field(
-            pus_tm.space_packet_header.data_length
-        )
-        if expected_packet_len > len(raw_telemetry):
-            LOGGER.warning(
-                f'PusTelemetry: Passed packet with length {len(raw_telemetry)} '
-                f'shorter than specified packet length in PUS header {expected_packet_len}'
-            )
-            raise ValueError
-        pus_tm.secondary_packet_header = PusTmSecondaryHeader.unpack(
-            header_start=raw_telemetry[SPACE_PACKET_HEADER_SIZE:],
-            pus_version=pus_version
-        )
-        if len(raw_telemetry) - 2 < \
-                pus_tm.secondary_packet_header.get_header_size() + SPACE_PACKET_HEADER_SIZE:
-            LOGGER.warning("Passed packet too short!")
-            raise ValueError
-        if pus_tm.get_packet_size() != len(raw_telemetry):
-            LOGGER.warning(
-                f'PusTelemetry: Packet length field '
-                f'{pus_tm.space_packet_header.data_length} might be invalid!'
-            )
-            LOGGER.warning(f'self.get_packet_size: {pus_tm.get_packet_size()}')
-            LOGGER.warning(f'len(raw_telemetry): {len(raw_telemetry)}')
-        pus_tm._source_data = raw_telemetry[
-            pus_tm.secondary_packet_header.get_header_size() + SPACE_PACKET_HEADER_SIZE:-2
-        ]
-        pus_tm._crc = \
-            raw_telemetry[len(raw_telemetry) - 2] << 8 | raw_telemetry[len(raw_telemetry) - 1]
-        pus_tm.print_info = ""
-        pus_tm.__perform_crc_check(raw_telemetry)
-        return pus_tm
-
-    def __str__(self):
-        return f"PUS TM[{self.secondary_packet_header.service_id}," \
-               f"{self.secondary_packet_header.subservice_id}] with message counter " \
-               f"{self.secondary_packet_header.message_counter}"
-
-    def __repr__(self):
-        return f"{self.__class__.__name__}(service={self.secondary_packet_header.service_id!r}, " \
-               f"subservice={self.secondary_packet_header.subservice_id!r})"
-
-    def get_service(self):
-        """
-        :return: Service ID
-        """
-        return self.secondary_packet_header.service_id
-
-    def get_subservice(self):
-        """
-        :return: Subservice ID
-        """
-        return self.secondary_packet_header.subservice_id
-
-    def is_valid(self):
-        return self._valid
-
-    def get_tm_data(self) -> bytearray:
-        """
-        :return: TM application data (raw)
-        """
-        return self._source_data
-
-    def get_packet_id(self):
-        return self.space_packet_header.packet_id
-
-    def __perform_crc_check(self, raw_telemetry: bytearray):
-        crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-        if len(raw_telemetry) < self.get_packet_size():
-            LOGGER.warning('Invalid packet length')
-            return
-        data_to_check = raw_telemetry[0:self.get_packet_size()]
-        crc = crc_func(data_to_check)
-        if crc == 0:
-            self._valid = True
-        else:
-            LOGGER.warning('Invalid CRC detected !')
-
-    def get_source_data_length(self, timestamp_len: int, pus_version: PusVersion) -> int:
-        """Retrieve size of TM packet data header in bytes.
-
-        Formula according to PUS Standard: C = (Number of octets in packet source data field) - 1.
-        The size of the TM packet is the size of the packet secondary header with
-        the timestamp + the length of the application data + PUS timestamp size +
-        length of the CRC16 checksum - 1
-        """
-        try:
-            if pus_version == PusVersion.PUS_A:
-                data_length = \
-                    PusTmSecondaryHeader.HEADER_SIZE_WITHOUT_TIME_PUS_A + \
-                    timestamp_len + len(self._source_data) + 1
-            else:
-                data_length = \
-                    PusTmSecondaryHeader.HEADER_SIZE_WITHOUT_TIME_PUS_C + \
-                    timestamp_len + len(self._source_data) + 1
-            return data_length
-        except TypeError:
-            print("PusTelecommand: Invalid type of application data!")
-            return 0
-
-    def specify_packet_info(self, print_info: str):
-        """Caches a print information string for later printing
-        :param print_info:
-        :return:
-        """
-        self.print_info = print_info
-
-    def append_packet_info(self, print_info: str):
-        """Similar to the function above, but appends to the existing information string.
-        :param print_info:
-        :return:
-        """
-        self.print_info = self.print_info + print_info
-
-    def append_telemetry_content(self, content_list: list):
-        """Default implementation adds the PUS header content to the list which can then be
-        printed with a simple print() command. To add additional content, override this method
-        (don't forget to still call this function with super() if the header is required)
-        :param content_list: Header content will be appended to this list
-        :return:
-        """
-        self.secondary_packet_header.append_data_field_header(content_list=content_list)
-        self.space_packet_header.append_space_packet_header_content(content_list=content_list)
-        if self.is_valid():
-            content_list.append("Yes")
-        else:
-            content_list.append("No")
-
-    def append_telemetry_column_headers(self, header_list: list):
-        """Default implementation adds the PUS header content header (confusing, I know)
-        to the list which can then be  printed with a simple print() command.
-        To add additional headers, override this method
-        (don't forget to still call this function with super() if the header is required)
-        :param header_list: Header content will be appended to this list
-        :return:
-        """
-        self.secondary_packet_header.append_data_field_header_column_header(header_list=header_list)
-        self.space_packet_header.append_space_packet_header_column_headers(header_list=header_list)
-        header_list.append("Packet valid")
-
-    def get_custom_printout(self) -> str:
-        """Can be used to supply any additional custom printout.
-        :return: String which will be printed by TmTcPrinter class as well as logged if specified
-        """
-        return ""
-
-    def get_packet_size(self) -> int:
-        """
-        :return: Size of the TM packet based on the space packet header data length field.
-        The space packet data field is the full length of data field minus one without the space packet header.
-        """
-        return SPACE_PACKET_HEADER_SIZE + self.space_packet_header.data_length + 1
-
-    def get_apid(self) -> int:
-        return self.space_packet_header.apid
-
-    def get_ssc(self) -> int:
-        """Get the source sequence count
-        :return: Source Sequence Count (see below, or PUS documentation)
-        """
-        return self.space_packet_header.ssc
-
-    def return_full_packet_string(self):
-        packet_raw = self.pack()
-        return get_printable_data_string(packet_raw, len(packet_raw))
-
-    def print_full_packet_string(self):
-        """Print the full TM packet in a clean format."""
-        packet_raw = self.pack()
-        print(get_printable_data_string(packet_raw, len(packet_raw)))
-
-    def print_source_data(self):
-        """Prints the TM source data in a clean format
-        :return:
-        """
-        print(get_printable_data_string(self._source_data, len(self._source_data)))
-
-    def return_source_data_string(self):
-        """Returns the source data string"""
-        return get_printable_data_string(self._source_data, len(self._source_data))
-
-
-class PusTmSecondaryHeader:
-    """Unpacks the PUS telemetry packet secondary header.
-
-    Currently only supports CDS short timestamps"""
-    HEADER_SIZE_WITHOUT_TIME_PUS_A = 4
-    HEADER_SIZE_WITHOUT_TIME_PUS_C = 7
-
-    def __init__(
-            self, pus_version: PusVersion, service_id: int, subservice_id: int,
-            time: CdsShortTimestamp, message_counter: int, destination_id: int = 0,
-            spacecraft_time_ref: int = 0,
-    ):
-        """Create a PUS telemetry secondary header object.
-
-        :param pus_version:
-        :param service_id:
-        :param subservice_id:
-        :param message_counter: 8 bit counter for PUS A, 16 bit counter for PUS C
-        :param spacecraft_time_ref: Space time reference if PUS C is used
-        :param time: Time field
-        """
-        self.pus_version = pus_version
-        self.spacecraft_time_ref = spacecraft_time_ref
-        if self.pus_version == PusVersion.PUS_A:
-            self.pus_version_number = 0
-        else:
-            self.pus_version_number = 1
-        self.service_id = service_id
-        self.subservice_id = subservice_id
-        if (self.pus_version == PusVersion.PUS_A and message_counter > 255) or \
-                (self.pus_version == PusVersion.PUS_C and message_counter > 65536):
-            raise ValueError
-        self.message_counter = message_counter
-        self.destination_id = destination_id
-        self.time = time
-
-    @classmethod
-    def __empty(cls) -> PusTmSecondaryHeader:
-        return PusTmSecondaryHeader(
-            pus_version=PusVersion.PUS_C,
-            service_id=-1,
-            subservice_id=-1,
-            time=CdsShortTimestamp.init_from_current_time(),
-            message_counter=0
-        )
-
-    def pack(self) -> bytearray:
-        secondary_header = bytearray()
-        if self.pus_version == PusVersion.PUS_A:
-            secondary_header.append((self.pus_version_number & 0x07) << 4)
-        elif self.pus_version == PusVersion.PUS_C:
-            secondary_header.append(self.pus_version_number << 4 | self.spacecraft_time_ref)
-        secondary_header.append(self.service_id)
-        secondary_header.append(self.subservice_id)
-        if self.pus_version == PusVersion.PUS_A:
-            secondary_header.append(self.message_counter)
-        elif self.pus_version == PusVersion.PUS_C:
-            secondary_header.append((self.message_counter & 0xff00) >> 8)
-            secondary_header.append(self.message_counter & 0xff)
-            secondary_header.append((self.destination_id & 0xff00) >> 8)
-            secondary_header.append(self.destination_id & 0xff)
-        secondary_header.extend(self.time.pack())
-        return secondary_header
-
-    @classmethod
-    def unpack(cls, header_start: bytearray, pus_version: PusVersion) -> PusTmSecondaryHeader:
-        """Unpack the PUS TM secondary header from the raw packet starting at the header index.
-        The user still needs to specify the PUS version because the version field is parsed
-        differently depending on the PUS version.
-
-        :param header_start:
-        :param pus_version:
-        :raises ValueError: bytearray too short or PUS version missmatch.
-        :return:
-        """
-        if pus_version == PusVersion.UNKNOWN:
-            pus_version = get_pus_tm_version()
-        secondary_header = cls.__empty()
-        current_idx = 0
-        if pus_version == PusVersion.PUS_A:
-            secondary_header.pus_version = PusVersion.PUS_A
-            secondary_header.pus_version_number = (header_start[current_idx] & 0x70) >> 4
-            if secondary_header.pus_version_number == 1:
-                LOGGER.warning(
-                    'PUS version field value 1 found where PUS A value (0) was expected!'
-                )
-                raise ValueError
-
-        elif pus_version == PusVersion.PUS_C:
-            secondary_header.pus_version = PusVersion.PUS_C
-            if secondary_header.pus_version_number == 0:
-                LOGGER.warning(
-                    'PUS version field value 0 found where PUS C value (1) was expected!'
-                )
-                raise ValueError
-            secondary_header.pus_version_number = (header_start[current_idx] & 0xF0) >> 4
-            secondary_header.spacecraft_time_ref = header_start[current_idx] & 0x0F
-        if len(header_start) < secondary_header.get_header_size():
-            LOGGER.warning(
-                f'Invalid PUS data field header size, '
-                f'less than expected {secondary_header.get_header_size()} bytes'
-            )
-            raise ValueError
-        current_idx += 1
-        secondary_header.service_id = header_start[current_idx]
-        current_idx += 1
-        secondary_header.subservice_id = header_start[current_idx]
-        current_idx += 1
-        if pus_version == PusVersion.PUS_A:
-            secondary_header.message_counter = header_start[current_idx]
-            current_idx += 1
-        else:
-            secondary_header.message_counter = \
-                header_start[current_idx] << 8 | header_start[current_idx + 1]
-            current_idx += 2
-        if pus_version == PusVersion.PUS_C:
-            secondary_header.destination_id = \
-                header_start[current_idx] << 8 | header_start[current_idx + 1]
-            current_idx += 2
-        # If other time formats are supported in the future, this information can be used
-        #  to unpack the correct time code
-        time_code_id = read_p_field(header_start[current_idx])
-        if time_code_id:
-            pass
-        secondary_header.time = CdsShortTimestamp.unpack(
-            time_field=header_start[current_idx: current_idx + PusTelemetry.PUS_TIMESTAMP_SIZE]
-        )
-        return secondary_header
-
-    def append_data_field_header(self, content_list: list):
-        """Append important data field header parameters to the passed content list.
-        :param content_list:
-        :return:
-        """
-        content_list.append(str(self.service_id))
-        content_list.append(str(self.subservice_id))
-        content_list.append(str(self.message_counter))
-        self.time.add_time_to_content_list(content_list=content_list)
-
-    def append_data_field_header_column_header(self, header_list: list):
-        """Append important data field header column headers to the passed list.
-        :param header_list:
-        :return:
-        """
-        header_list.append("Service")
-        header_list.append("Subservice")
-        header_list.append("Subcounter")
-        self.time.add_time_headers_to_header_list(header_list=header_list)
-
-    def get_header_size(self):
-        if self.pus_version == PusVersion.PUS_A:
-            return PusTelemetry.PUS_TIMESTAMP_SIZE + 4
-        else:
-            return PusTelemetry.PUS_TIMESTAMP_SIZE + 7
-
-
-def get_printable_data_string(byte_array: bytearray, length: int) -> str:
-    """Returns the TM data in a clean printable string format
-    Prints payload data in default mode
-    and prints the whole packet if full_packet = True is passed.
-    :return:
-    """
-    str_to_print = "["
-    for index in range(length):
-        str_to_print += str(hex(byte_array[index])) + " , "
-    str_to_print = str_to_print.rstrip()
-    str_to_print = str_to_print.rstrip(',')
-    str_to_print = str_to_print.rstrip()
-    str_to_print += "]"
-    return str_to_print
-
-
-class PusTmBase(PusTmInterface):
-    def __init__(self, pus_tm: PusTelemetry):
-        self.pus_tm = pus_tm
-
-    @abstractmethod
-    def pack(self) -> bytearray:
-        return self.pus_tm.pack()
-
-    @abstractmethod
-    def get_tm_data(self) -> bytearray:
-        return self.pus_tm.get_tm_data()
-
-    @abstractmethod
-    def get_ssc(self) -> int:
-        return self.pus_tm.get_ssc()
-
-    @abstractmethod
-    def is_valid(self):
-        return self.pus_tm.is_valid()
-
-    @abstractmethod
-    def get_apid(self) -> int:
-        return self.pus_tm.get_apid()
-
-    @abstractmethod
-    def get_service(self) -> int:
-        return self.pus_tm.get_service()
-
-    @abstractmethod
-    def get_subservice(self) -> int:
-        return self.pus_tm.get_subservice()
-
-
-class PusTmInfoBase(PusTmInfoInterface):
-    def __init__(self, pus_tm: PusTelemetry):
-        self.pus_tm = pus_tm
-
-    @abstractmethod
-    def get_print_info(self) -> str:
-        return self.pus_tm.print_info
-
-    @abstractmethod
-    def get_custom_printout(self) -> str:
-        return self.pus_tm.get_custom_printout()
-
-    @abstractmethod
-    def return_source_data_string(self) -> str:
-        return self.pus_tm.return_source_data_string()
-
-    @abstractmethod
-    def specify_packet_info(self, print_info: str):
-        self.pus_tm.print_info = print_info
-
-    @abstractmethod
-    def append_packet_info(self, info: str):
-        self.pus_tm.print_info += info
-
-    @abstractmethod
-    def append_telemetry_column_headers(self, header_list: list):
-        self.pus_tm.append_telemetry_column_headers(header_list=header_list)
-
-    @abstractmethod
-    def append_telemetry_content(self, content_list: list):
-        self.pus_tm.append_telemetry_content(content_list=content_list)
-
-
-# Structure of a PUS Packet :
-# A PUS packet consists of consecutive bits, the allocation and structure is standardised.
-# Extended information can be found in ECSS-E-70-41A  on p.46
-# The easiest form to send a PUS Packet is in hexadecimal form.
-# A two digit hexadecimal number equals one byte, 8 bits or one octet
-# o = optional, Srv = Service
-#
-# The structure is shown as follows for TM[17,2]
-# 1. Structure Header
-# 2. Structure Subheader
-# 3. Component (size in bits)
-# 4. Hexadecimal number
-# 5. Binary Number
-# 6. Decimal Number
-#
-# Packet Structure for PUS A:
-#
-# -------------------------------------------Packet Header(48)------------------------------------------|   Packet   |
-#  ----------------Packet ID(16)----------------------|Packet Sequence Control (16)| Packet Length (16) | Data Field |
-# Version       | Type(1) |Data Field    |APID(11)    | SequenceFlags(2) |Sequence |                    | (Variable) |
-# Number(3)     |         |Header Flag(1)|            |                  |Count(14)|                    |            |
-#           0x08               |    0x73              |       0xc0       | 0x19    |   0x00  |   0x04   |            |
-#    000      0      1      000|  01110011            | 11  000000       | 00011001|00000000 | 0000100  |            |
-#     0   |   0   |  1     |    115(ASCII s)          | 3 |            25          |   0     |    4     |            |
-#
-#   - Packet Length is an unsigned integer C = Number of Octets in Packet Data Field - 1
-#
-# Packet Data Field Structure:
-#
-# ------------------------------------------------Packet Data Field------------------------------------------------- |
-# ---------------------------------Data Field Header --------------------------------------|AppData|Spare|PacketErrCtr |
-# Spare(1)|TM PUS Ver.(3)|Spare(4)|SrvType (8)|SrvSubtype(8)|Subcounter(8)|Time(7)|Spare(o)|(var)  |(var)|  (16)       |
-#        0x11 (0x1F)              |  0x11     |   0x01      |             |       |        |       |     |     Calc.   |
-#    0     001     0000           |00010001   | 00000001    |             |       |        |       |     |             |
-#    0      1       0             |    17     |     2       |             |       |        |       |     |             |
-#
-# - Thus subcounter is specified optional for PUS A, but for this implementation it is expected the subcounter
-#   is contained in the raw packet
-# - In PUS A, the destination ID can be present as one byte in the spare field. It was omitted for the FSFW
-# - In PUS C, the last spare bits of the first byte are replaced by the space time reference field
-# - PUS A and PUS C both use the CDS short seven byte timestamp in the time field
-# - PUS C has a 16 bit counter sequence counter and a 16 bit destination ID before the time field
diff --git a/src/tmtccmd/sendreceive/cmd_sender_receiver.py b/src/tmtccmd/sendreceive/cmd_sender_receiver.py
index e95bc5a9..b4dec13f 100644
--- a/src/tmtccmd/sendreceive/cmd_sender_receiver.py
+++ b/src/tmtccmd/sendreceive/cmd_sender_receiver.py
@@ -21,9 +21,7 @@
 from tmtccmd.ccsds.handler import CcsdsTmHandler
 from tmtccmd.sendreceive.tm_listener import TmListener
 from tmtccmd.tc.definitions import TcQueueEntryT
-from tmtccmd.tm.definitions import TelemetryQueueT
 from tmtccmd.core.globals_manager import get_global
-from tmtccmd.ecss.tm import PusTelemetry
 
 LOGGER = get_console_logger()
 
@@ -35,8 +33,8 @@ class CommandSenderReceiver:
     for example specific implementations (e.g. SingleCommandSenderReceiver)
     """
     def __init__(
-            self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter, tm_listener: TmListener,
-            tm_handler: CcsdsTmHandler
+            self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
+            tm_listener: TmListener, tm_handler: CcsdsTmHandler, apid: int
     ):
 
         """
@@ -47,6 +45,7 @@ def __init__(
         self._tm_timeout = get_global(CoreGlobalIds.TM_TIMEOUT)
         self._tm_handler = tm_handler
         self._tc_send_timeout_factor = get_global(CoreGlobalIds.TC_SEND_TIMEOUT_FACTOR)
+        self._apid = apid
 
         if isinstance(com_if, CommunicationInterface):
             self._com_if = com_if
@@ -213,7 +212,7 @@ def _check_for_timeout(self, last_timeout: bool = True):
             from tmtccmd.core.globals_manager import get_global
             if get_global(CoreGlobalIds.RESEND_TC):
                 LOGGER.info("CommandSenderReceiver: Timeout, sending TC again !")
-                self._com_if.send_telecommand(self._last_tc, self._last_tc_obj)
+                self._com_if.send(self._last_tc)
                 self._timeout_counter = self._timeout_counter + 1
                 self._start_time = time.time()
             else:
@@ -221,11 +220,13 @@ def _check_for_timeout(self, last_timeout: bool = True):
                 self._reply_received = True
         time.sleep(0.5)
 
-    def print_tm_queue(self, tm_queue: TelemetryQueueT):
-        while tm_queue:
-            try:
-                tm_packet_list = tm_queue.pop()
-                for tm_packet in tm_packet_list:
-                    self._tmtc_printer.print_telemetry(PusTelemetry(tm_packet))
-            except AttributeError as e:
-                LOGGER.exception("CommandSenderReceiver Exception: Invalid queue entry. Traceback:", e)
+    # TODO: Move to TMTC printer to decouple this module?
+    # def print_tm_queue(self, tm_queue: TelemetryQueueT):
+    #    while tm_queue:
+    #        try:
+    #            tm_packet_list = tm_queue.pop()
+    #            for tm_packet in tm_packet_list:
+    #                telemetry = PusTelemetry(tm_packet)
+    #                self._tmtc_printer.print_telemetry()
+    #        except AttributeError as e:
+    #            LOGGER.exception("CommandSenderReceiver Exception: Invalid queue entry. Traceback:", e)
diff --git a/src/tmtccmd/sendreceive/multiple_cmds_sender_receiver.py b/src/tmtccmd/sendreceive/multiple_cmds_sender_receiver.py
index 73dc1c87..1c70f8c7 100644
--- a/src/tmtccmd/sendreceive/multiple_cmds_sender_receiver.py
+++ b/src/tmtccmd/sendreceive/multiple_cmds_sender_receiver.py
@@ -1,5 +1,4 @@
-"""
-Used to send multiple TCs as bursts and listen for replies simultaneously. Used by Module Tester
+"""Used to send multiple TCs as bursts and listen for replies simultaneously. Used by Module Tester
 """
 import sys
 import time
@@ -26,7 +25,9 @@ class MultipleCommandSenderReceiver(SequentialCommandSenderReceiver):
     def __init__(self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
                  tc_queue: Deque, tm_listener: TmListener, wait_intervals: list,
                  wait_time: Union[float, list], print_tm: bool):
-        """TCs are sent in burst when applicable. Wait intervals can be specified by supplying respective arguments
+        """TCs are sent in burst when applicable. Wait intervals can be specified by supplying
+        respective arguments
+
         :param com_if:
         :param tmtc_printer:
         :param tc_queue:
@@ -36,8 +37,9 @@ def __init__(self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
         :param wait_time: List of wait times or uniform wait time as float
         :param print_tm:
         """
-        super().__init__(com_if=com_if, tmtc_printer=tmtc_printer,
-                         tm_listener=tm_listener, tc_queue=tc_queue)
+        super().__init__(
+            com_if=com_if, tmtc_printer=tmtc_printer, tm_listener=tm_listener, tc_queue=tc_queue
+        )
         self.waitIntervals = wait_intervals
         self.waitTime = wait_time
         self.printTm = print_tm
diff --git a/src/tmtccmd/sendreceive/sequential_sender_receiver.py b/src/tmtccmd/sendreceive/sequential_sender_receiver.py
index d088e543..2b92acd8 100644
--- a/src/tmtccmd/sendreceive/sequential_sender_receiver.py
+++ b/src/tmtccmd/sendreceive/sequential_sender_receiver.py
@@ -21,17 +21,19 @@
 class SequentialCommandSenderReceiver(CommandSenderReceiver):
     """Specific implementation of CommandSenderReceiver to send multiple telecommands in sequence"""
     def __init__(
-            self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter, tm_handler: CcsdsTmHandler,
-            apid: int, tm_listener: TmListener, tc_queue: TcQueueT):
+            self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
+            tm_handler: CcsdsTmHandler, apid: int, tm_listener: TmListener, tc_queue: TcQueueT):
         """
         :param com_if:          CommunicationInterface object, passed on to CommandSenderReceiver
-        :param tm_listener:     TmListener object which runs in the background and receives all Telemetry
-        :param tmtc_printer:    TmTcPrinter object, passed on to CommandSenderReceiver for this time period
+        :param tm_listener:     TmListener object which runs in the background and receives
+                                all Telemetry
+        :param tmtc_printer:    TmTcPrinter object, passed on to CommandSenderReceiver for
+                                this time period
         """
         super().__init__(
-            com_if=com_if, tmtc_printer=tmtc_printer, tm_listener=tm_listener, tm_handler=tm_handler
+            com_if=com_if, tmtc_printer=tmtc_printer, tm_listener=tm_listener,
+            tm_handler=tm_handler, apid=apid
         )
-        self._apid = apid
         self._tc_queue = tc_queue
         self.__all_replies_received = False
 
diff --git a/src/tmtccmd/sendreceive/single_command_sender_receiver.py b/src/tmtccmd/sendreceive/single_command_sender_receiver.py
index 6e66254e..f1e3719f 100644
--- a/src/tmtccmd/sendreceive/single_command_sender_receiver.py
+++ b/src/tmtccmd/sendreceive/single_command_sender_receiver.py
@@ -7,7 +7,7 @@
 @brief
     Used to send single tcs and listen for replies after that
 """
-
+from tmtccmd.ccsds.handler import CcsdsTmHandler
 from tmtccmd.sendreceive.cmd_sender_receiver import CommandSenderReceiver
 from tmtccmd.sendreceive.tm_listener import TmListener
 
@@ -27,15 +27,19 @@ class SingleCommandSenderReceiver(CommandSenderReceiver):
     Specific implementation of CommandSenderReceiver to send a single telecommand
     This object can be used by instantiating it and calling sendSingleTcAndReceiveTm()
     """
-    def __init__(self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
-                 tm_listener: TmListener):
+    def __init__(
+            self, com_if: CommunicationInterface, tmtc_printer: TmTcPrinter,
+            tm_listener: TmListener, tm_handler: CcsdsTmHandler, apid: int
+    ):
         """
         :param com_if: CommunicationInterface object, passed on to CommandSenderReceiver
         :param tm_listener: TmListener object which runs in the background and receives all TM
         :param tmtc_printer: TmTcPrinter object, passed on to CommandSenderReceiver
         """
-        super().__init__(com_if=com_if, tm_listener=tm_listener,
-                         tmtc_printer=tmtc_printer)
+        super().__init__(
+            com_if=com_if, tm_listener=tm_listener, tmtc_printer=tmtc_printer,
+            tm_handler=tm_handler,apid=apid
+        )
 
     def send_single_tc_and_receive_tm(self, pus_packet_tuple: PusTcTupleT):
         """
@@ -49,15 +53,20 @@ def send_single_tc_and_receive_tm(self, pus_packet_tuple: PusTcTupleT):
             return
         self._operation_pending = True
         self._tm_listener.set_listener_mode(TmListener.ListenerModes.SEQUENCE)
-        self._tmtc_printer.print_telecommand(tc_packet_obj=pus_packet_obj, tc_packet_raw=pus_packet_raw)
-        self._com_if.send_telecommand(tc_packet=pus_packet_raw, tc_packet_obj=pus_packet_obj)
+        self._tmtc_printer.print_telecommand(
+            tc_packet_obj=pus_packet_obj, tc_packet_raw=pus_packet_raw
+        )
+        self._com_if.send(data=pus_packet_raw)
         self._last_tc = pus_packet_raw
         self._last_tc_obj = pus_packet_obj
         while self._operation_pending:
             # wait until reply is received
             super()._check_for_first_reply()
         if self._reply_received:
-            self._tm_listener.event_mode_op_finished.set()
-            self.print_tm_queue(self._tm_listener.retrieve_tm_packet_queue())
+            self._tm_listener.set_mode_op_finished()
+            packet_queue = self._tm_listener.retrieve_ccsds_tm_packet_queue(
+                apid=self._apid, clear=True
+            )
+            self._tm_handler.handle_ccsds_packet_queue(apid=self._apid, packet_queue=packet_queue)
             logger.info("SingleCommandSenderReceiver: Reply received")
             logger.info("Listening for packages ...")
diff --git a/src/tmtccmd/sendreceive/tm_listener.py b/src/tmtccmd/sendreceive/tm_listener.py
index a5f51e43..e7a77b05 100644
--- a/src/tmtccmd/sendreceive/tm_listener.py
+++ b/src/tmtccmd/sendreceive/tm_listener.py
@@ -11,6 +11,8 @@
 from typing import Dict, List, Tuple
 from enum import Enum
 
+from spacepackets.ccsds.spacepacket import get_apid_from_raw_space_packet
+
 from tmtccmd.tm.definitions import TelemetryQueueT, TelemetryListT, TmTypes
 from tmtccmd.utility.logger import get_console_logger
 from tmtccmd.com_if.com_interface_base import CommunicationInterface
@@ -75,7 +77,7 @@ def __init__(
         self.__listener_mode = self.ListenerModes.LISTENER
         self.__tm_type = tm_type
         self.__queue_dict: QueueDictT = dict({
-            UNKNOWN_TARGET_ID: [deque(), self.DEFAULT_UNKNOWN_QUEUE_MAX_LEN]
+            UNKNOWN_TARGET_ID: (deque(), self.DEFAULT_UNKNOWN_QUEUE_MAX_LEN)
         })
 
     def start(self):
@@ -91,7 +93,7 @@ def stop(self):
 
     def subscribe_ccsds_tm_handler(self, apid: int, queue_max_len: int):
         if self.__tm_type == TmTypes.CCSDS_SPACE_PACKETS:
-            self.__queue_dict[apid] = [deque(), queue_max_len]
+            self.__queue_dict[apid] = (deque(), queue_max_len)
         else:
             LOGGER.warning("This function only support CCSDS space packet handling")
 
@@ -191,7 +193,7 @@ def clear_ccsds_tm_packet_queue(self, apid: int):
                     f'TmListener: Blocked on lock acquisition for longer than'
                     f'{self.DEFAULT_LOCK_TIMEOUT} second!'
                 )
-            target_queue.clear()
+            target_queue[0].clear()
 
     def clear_tm_packet_queues(self, lock: bool):
         locked = False
@@ -212,7 +214,7 @@ def check_for_one_telemetry_sequence(self) -> bool:
         """Receive all telemetry for a specified time period.
         :return: True if a sequence was received
         """
-        data_available = self.__com_if.data_available(0)
+        data_available = self.__com_if.data_available(timeout=0, parameters=None)
         if data_available == 0:
             return False
         elif data_available > 0:
@@ -299,7 +301,7 @@ def __read_telemetry_sequence(self):
             if self.__event_mode_op_finished.is_set():
                 if self.__listener_mode == self.ListenerModes.SEQUENCE:
                     return
-            packets_available = self.__com_if.data_available(0.2)
+            packets_available = self.__com_if.data_available(timeout=0.2, parameters=None)
             if packets_available > 0:
                 packet_list = self.__com_if.receive()
                 with acquire_timeout(self.lock_listener, timeout=self.DEFAULT_LOCK_TIMEOUT) as acquired:
@@ -336,7 +338,6 @@ def __route_packets(self, tm_packet_list: TelemetryListT):
             unknown_target_queue.appendleft(tm_packet)
 
     def __handle_ccsds_space_packet(self, tm_packet: bytearray) -> bool:
-        from tmtccmd.ccsds.spacepacket import get_apid_from_raw_space_packet
         if len(tm_packet) < 6:
             LOGGER.warning('TM packet to small to be a CCSDS space packet')
         else:
diff --git a/src/tmtccmd/tc/definitions.py b/src/tmtccmd/tc/definitions.py
index 4f9f74fd..6652a6c0 100644
--- a/src/tmtccmd/tc/definitions.py
+++ b/src/tmtccmd/tc/definitions.py
@@ -1,6 +1,6 @@
 from typing import Tuple, Union, Deque
 from tmtccmd.config.definitions import QueueCommands
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 
 TcAuxiliaryTupleT = Tuple[QueueCommands, any]
 PusTcTupleT = Tuple[bytearray, Union[None, PusTelecommand]]
diff --git a/src/tmtccmd/tc/packer.py b/src/tmtccmd/tc/packer.py
index 781de68f..27062a34 100644
--- a/src/tmtccmd/tc/packer.py
+++ b/src/tmtccmd/tc/packer.py
@@ -8,7 +8,7 @@
 from typing import Union
 
 from tmtccmd.tc.definitions import TcQueueT
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 from tmtccmd.utility.logger import get_console_logger
 from tmtccmd.tc.service_17_test import pack_service17_ping_command
 from tmtccmd.tc.service_5_event import pack_generic_service5_test_into
diff --git a/src/tmtccmd/tc/service_200_mode.py b/src/tmtccmd/tc/service_200_mode.py
index cf43acd0..0d966498 100644
--- a/src/tmtccmd/tc/service_200_mode.py
+++ b/src/tmtccmd/tc/service_200_mode.py
@@ -1,16 +1,23 @@
 """
 @brief      Core components for mode commanding (custom PUS service)
 """
+import enum
 import struct
 
 
-def pack_mode_data(object_id: bytearray, mode_: int, submode_: int) -> bytearray:
-    """
-    Mode 0: Off, Mode 1: Mode On, Mode 2: Mode Normal, Mode 3: Mode Raw
+class Modes(enum.IntEnum):
+    OFF = 0,
+    ON = 1,
+    NORMAL = 2,
+    RAW = 3
+
+
+def pack_mode_data(object_id: bytearray, mode: Modes, submode: int) -> bytearray:
+    """Mode 0: Off, Mode 1: Mode On, Mode 2: Mode Normal, Mode 3: Mode Raw
     """
     # Normal mode
-    mode = struct.pack(">I", mode_)
+    mode_packed = struct.pack("!I", mode)
     # Submode default
-    submode = struct.pack('B', submode_)
-    mode_data = object_id + mode + submode
+    submode_byte = struct.pack('B', submode)
+    mode_data = object_id + mode_packed + submode_byte
     return mode_data
diff --git a/src/tmtccmd/tc/service_20_parameter.py b/src/tmtccmd/tc/service_20_parameter.py
index 47387efb..a6ab75a0 100644
--- a/src/tmtccmd/tc/service_20_parameter.py
+++ b/src/tmtccmd/tc/service_20_parameter.py
@@ -2,7 +2,7 @@
 """
 from typing import Union
 
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 from tmtccmd.pus.service_20_parameter import EcssPtc, EcssPfcUnsigned
 from tmtccmd.utility.logger import get_console_logger
 from tmtccmd.config.globals import get_global_apid
diff --git a/src/tmtccmd/tc/service_3_housekeeping.py b/src/tmtccmd/tc/service_3_housekeeping.py
index 096c3e53..65b7a091 100644
--- a/src/tmtccmd/tc/service_3_housekeeping.py
+++ b/src/tmtccmd/tc/service_3_housekeeping.py
@@ -3,7 +3,7 @@
 import enum
 import struct
 
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 
 
 class Srv3Subservice(enum.IntEnum):
diff --git a/src/tmtccmd/tc/service_8_functional_cmd.py b/src/tmtccmd/tc/service_8_functional_cmd.py
index f8f41923..fc9fb323 100644
--- a/src/tmtccmd/tc/service_8_functional_cmd.py
+++ b/src/tmtccmd/tc/service_8_functional_cmd.py
@@ -11,7 +11,7 @@ class Srv8Subservices(enum.IntEnum):
 
 
 def generate_action_command(
-        object_id: bytearray, action_id: int, app_data: bytearray = bytearray([]),
+        object_id: bytes, action_id: int, app_data: bytes = bytes(),
         ssc: int = 0, apid: int = -1
 ) -> PusTelecommand:
     if apid == -1:
diff --git a/src/tmtccmd/tm/__init__.py b/src/tmtccmd/tm/__init__.py
index c98c0148..494799c5 100644
--- a/src/tmtccmd/tm/__init__.py
+++ b/src/tmtccmd/tm/__init__.py
@@ -1,10 +1,9 @@
 from tmtccmd.tm.definitions import TelemetryListT, TelemetryQueueT
 
 from tmtccmd.tm.service_1_verification import Service1TM
-from tmtccmd.tm.service_5_event import Service5TM, Srv5Severity, Srv5Subservices
+from tmtccmd.tm.service_5_event import Service5TM
 from tmtccmd.tm.service_3_base import Service3Base
 from tmtccmd.tm.service_3_housekeeping import Service3TM
 from tmtccmd.tm.service_17_test import Service17TM
 from tmtccmd.tm.service_8_functional_cmd import Service8TM
 from tmtccmd.tm.service_23_file_mgmt import Service23TM
-from tmtccmd.ccsds.time import CdsShortTimestamp
diff --git a/src/tmtccmd/tm/base.py b/src/tmtccmd/tm/base.py
index 637c3e4a..310bd874 100644
--- a/src/tmtccmd/tm/base.py
+++ b/src/tmtccmd/tm/base.py
@@ -1,6 +1,8 @@
 from abc import abstractmethod
 from typing import Optional
 
+from spacepackets.ecss.tm import PusTelemetry
+
 
 class PusTmInterface:
 
@@ -61,3 +63,55 @@ def append_telemetry_column_headers(self, header_list: list):
     @abstractmethod
     def append_telemetry_content(self, content_list: list):
         pass
+
+
+class PusTmBase(PusTmInterface):
+    def __init__(self, pus_tm: PusTelemetry):
+        self.pus_tm = pus_tm
+
+    def pack(self) -> bytearray:
+        return self.pus_tm.pack()
+
+    def get_tm_data(self) -> bytearray:
+        return self.pus_tm.get_tm_data()
+
+    def get_ssc(self) -> int:
+        return self.pus_tm.get_ssc()
+
+    def is_valid(self):
+        return self.pus_tm.is_valid()
+
+    def get_apid(self) -> int:
+        return self.pus_tm.get_apid()
+
+    def get_service(self) -> int:
+        return self.pus_tm.get_service()
+
+    def get_subservice(self) -> int:
+        return self.pus_tm.get_subservice()
+
+
+class PusTmInfoBase(PusTmInfoInterface):
+    def __init__(self, pus_tm: PusTelemetry):
+        self.pus_tm = pus_tm
+
+    def get_print_info(self) -> str:
+        return self.pus_tm.print_info
+
+    def get_custom_printout(self) -> str:
+        return self.pus_tm.get_custom_printout()
+
+    def return_source_data_string(self) -> str:
+        return self.pus_tm.return_source_data_string()
+
+    def specify_packet_info(self, print_info: str):
+        self.pus_tm.print_info = print_info
+
+    def append_packet_info(self, info: str):
+        self.pus_tm.print_info += info
+
+    def append_telemetry_column_headers(self, header_list: list):
+        self.pus_tm.append_telemetry_column_headers(header_list=header_list)
+
+    def append_telemetry_content(self, content_list: list):
+        self.pus_tm.append_telemetry_content(content_list=content_list)
diff --git a/src/tmtccmd/tm/definitions.py b/src/tmtccmd/tm/definitions.py
index 34996661..5bdd9777 100644
--- a/src/tmtccmd/tm/definitions.py
+++ b/src/tmtccmd/tm/definitions.py
@@ -1,6 +1,6 @@
 import enum
 from typing import Deque, Tuple, List, Union
-from tmtccmd.ecss.tm import PusTelemetry
+from spacepackets.ecss.tm import PusTelemetry
 from tmtccmd.tm.base import PusTmInfoInterface, PusTmInterface
 
 TelemetryListT = List[bytearray]
diff --git a/src/tmtccmd/tm/handler.py b/src/tmtccmd/tm/handler.py
index c332a23e..b4a058ad 100644
--- a/src/tmtccmd/tm/handler.py
+++ b/src/tmtccmd/tm/handler.py
@@ -1,5 +1,5 @@
 from tmtccmd.tm.definitions import TmTypes
-from tmtccmd.ecss.tm import PusTelemetry
+from spacepackets.ecss.tm import PusTelemetry
 from tmtccmd.tm.service_5_event import Service5TM
 from tmtccmd.tm.service_1_verification import Service1TM
 from tmtccmd.tm.service_17_test import Service17TM
@@ -26,12 +26,12 @@ def default_factory_hook(raw_tm_packet: bytearray, tmtc_printer: TmTcPrinter):
     service_type = raw_tm_packet[7]
     tm_packet = None
     if service_type == 1:
-        tm_packet = Service1TM(raw_tm_packet)
+        tm_packet = Service1TM.unpack(raw_telemetry=raw_tm_packet)
     if service_type == 5:
-        tm_packet = Service5TM(raw_tm_packet)
+        tm_packet = Service5TM.unpack(raw_telemetry=raw_tm_packet)
     if service_type == 17:
-        tm_packet = Service17TM(raw_tm_packet)
+        tm_packet = Service17TM.unpack(raw_telemetry=raw_tm_packet)
     if tm_packet is None:
         LOGGER.info(f'The service {service_type} is not implemented in Telemetry Factory')
-        tm_packet = PusTelemetry(raw_tm_packet)
-    tmtc_printer.print_telemetry(packet=tm_packet)
+        tm_packet = PusTelemetry.unpack(raw_telemetry=raw_tm_packet)
+    tmtc_printer.print_telemetry(packet_if=tm_packet, info_if=tm_packet)
diff --git a/src/tmtccmd/tm/service_1_verification.py b/src/tmtccmd/tm/service_1_verification.py
index bea5cd88..0bace147 100644
--- a/src/tmtccmd/tm/service_1_verification.py
+++ b/src/tmtccmd/tm/service_1_verification.py
@@ -6,8 +6,10 @@
 import struct
 from typing import Deque
 
-from tmtccmd.ecss.tm import PusTelemetry, PusVersion, PusTmInfoBase, PusTmBase
-from tmtccmd.ccsds.time import CdsShortTimestamp
+from spacepackets.ccsds.time import CdsShortTimestamp
+from spacepackets.ecss.tm import PusTelemetry, PusVersion
+
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.utility.logger import get_console_logger
 
 LOGGER = get_console_logger()
@@ -62,6 +64,13 @@ def __empty(cls):
     def unpack(
             cls, raw_telemetry: bytearray, pus_version: PusVersion = PusVersion.UNKNOWN
     ) -> Service1TM:
+        """Parse a service 1 telemetry packet
+
+        :param raw_telemetry:
+        :param pus_version:
+        :raises ValueError: Raw telemetry too short
+        :return:
+        """
         service_1_tm = cls.__empty()
         service_1_tm.pus_tm = PusTelemetry.unpack(
             raw_telemetry=raw_telemetry, pus_version=pus_version
@@ -108,26 +117,37 @@ def append_telemetry_column_headers(self, header_list: list):
             header_list.append("Step Number")
 
     def __handle_failure_verification(self):
+        """Handle parsing a verification failure packet, subservice ID 2, 4, 6 or 8
+        """
         self.specify_packet_info("Failure Verficiation")
         self.has_tc_error_code = True
         tm_data = self.get_tm_data()
-        if self.get_subservice() == 2:
+        subservice = self.get_subservice()
+        expected_len = 14
+        if subservice == 2:
             self.append_packet_info(" : Acceptance failure")
-        elif self.get_subservice() == 4:
+        elif subservice == 4:
             self.append_packet_info(" : Start failure")
-        elif self.get_subservice() == 6:
+        elif subservice == 6:
             self.is_step_reply = True
+            expected_len = 15
             self.append_packet_info(" : Step Failure")
-            self.step_number = struct.unpack('>B', tm_data[4:5])[0]
-            self.err_code = struct.unpack('>H', tm_data[5:7])[0]
-            self.error_param1 = struct.unpack('>I', tm_data[7:11])[0]
-            self.error_param2 = struct.unpack('>I', tm_data[11:15])[0]
-        elif self.get_subservice() == 8:
-            self.err_code = struct.unpack('>H', tm_data[4:6])[0]
-            self.error_param1 = struct.unpack('>I', tm_data[6:10])[0]
-            self.error_param2 = struct.unpack('>I', tm_data[10:14])[0]
+        elif subservice == 8:
+            self.append_packet_info(" : Completion Failure")
         else:
             LOGGER.error("Service1TM: Invalid subservice")
+        if len(tm_data) < expected_len:
+            LOGGER.warning(f'PUS TM[1,{subservice}] source data smaller than expected 15 bytes')
+            raise ValueError
+        current_idx = 4
+        if self.is_step_reply:
+            self.step_number = struct.unpack('>B', tm_data[current_idx: current_idx + 1])[0]
+            current_idx += 1
+        self.err_code = struct.unpack('>H', tm_data[current_idx: current_idx + 2])[0]
+        current_idx += 2
+        self.error_param1 = struct.unpack('>I', tm_data[current_idx: current_idx + 4])[0]
+        current_idx += 2
+        self.error_param2 = struct.unpack('>I', tm_data[current_idx: current_idx + 4])[0]
 
     def __handle_success_verification(self):
         self.pus_tm.specify_packet_info("Success Verification")
diff --git a/src/tmtccmd/tm/service_200_mode.py b/src/tmtccmd/tm/service_200_mode.py
index ae332872..86b5e075 100644
--- a/src/tmtccmd/tm/service_200_mode.py
+++ b/src/tmtccmd/tm/service_200_mode.py
@@ -4,7 +4,8 @@
 import struct
 
 from tmtccmd.pus.service_list import PusServices
-from tmtccmd.ecss.tm import PusTelemetry, PusTmBase, PusTmInfoBase, PusVersion, CdsShortTimestamp
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 
 
 class Service200TM(PusTmBase, PusTmInfoBase):
diff --git a/src/tmtccmd/tm/service_20_parameters.py b/src/tmtccmd/tm/service_20_parameters.py
index 26b474d6..b26b6d06 100644
--- a/src/tmtccmd/tm/service_20_parameters.py
+++ b/src/tmtccmd/tm/service_20_parameters.py
@@ -3,7 +3,9 @@
 import struct
 
 from tmtccmd.pus.service_list import PusServices
-from tmtccmd.ecss.tm import PusTelemetry, PusTmBase, PusTmInfoBase, PusVersion, CdsShortTimestamp
+from tmtccmd.pus.obj_id import ObjectId
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.utility.logger import get_console_logger
 
 LOGGER = get_console_logger()
@@ -21,12 +23,13 @@ def __init__(self):
         self.row = 0,
         self.param: any = 0
 
-    def pack(self) -> bytearray:
-        pass
+    # def pack(self) -> bytearray:
+    #     pass
+
+    # @classmethod
+    # def unpack(cls, raw_param: bytearray) -> ParamStruct:
+    #    return cls()
 
-    @classmethod
-    def unpack(cls, raw_param: bytearray) -> ParamStruct:
-        return cls()
 
 class Service20TM(PusTmInfoBase, PusTmBase):
     def __init__(
@@ -54,9 +57,15 @@ def __init__(
             destination_id=destination_id
         )
 
-        self.object_id = object_id
+        self.object_id = ObjectId.from_bytes(obj_id_as_bytes=object_id)
         self.param_struct = ParamStruct()
+        self.param_struct.param_id = param_id
+        self.param_struct.domain_id = domain_id
+        self.param_struct.unique_id = unique_id
+        self.param_struct.linear_index = linear_index
         self.__init_without_base(instance=self)
+        PusTmBase.__init__(self, pus_tm=pus_tm)
+        PusTmInfoBase.__init__(self, pus_tm=pus_tm)
         self.specify_packet_info("Parameter Service Reply")
 
     @staticmethod
@@ -101,7 +110,7 @@ def __empty(cls) -> Service20TM:
         return cls(
             subservice_id=-1,
             object_id=bytearray(4),
-            param_id=0,
+            param_id=bytearray(),
             domain_id=0,
             unique_id=0,
             linear_index=0
@@ -120,7 +129,7 @@ def unpack(
 
     def append_telemetry_content(self, content_list: list):
         super().append_telemetry_content(content_list=content_list)
-        content_list.append(hex(self.object_id))
+        content_list.append(self.object_id.as_string())
 
     def append_telemetry_column_headers(self, header_list: list):
         super().append_telemetry_column_headers(header_list=header_list)
@@ -138,16 +147,19 @@ def get_custom_printout(self) -> str:
             header_list.append("CCSDS Type")
             header_list.append("Columns")
             header_list.append("Rows")
-            # TODO: For more complex parameters like vectors or matrices, special handling would be nice
+            # TODO: For more complex parameters like vectors or matrices,
+            #       special handling would be nice
             header_list.append("Parameter")
 
-            content_list.append(self.domain_id)
-            content_list.append(self.unique_id)
-            content_list.append(self.linear_index)
-            content_list.append("PTC: " + str(self.type_ptc) + " | PFC: " + str(self.type_pfc))
-            content_list.append(self.column)
-            content_list.append(self.row)
-            content_list.append(self.param)
+            content_list.append(self.param_struct.domain_id)
+            content_list.append(self.param_struct.unique_id)
+            content_list.append(self.param_struct.linear_index)
+            content_list.append(
+                f"PTC: {self.param_struct.type_ptc} | PFC: {self.param_struct.type_pfc}"
+            )
+            content_list.append(self.param_struct.column)
+            content_list.append(self.param_struct.row)
+            content_list.append(self.param_struct.param)
 
             custom_printout += f"{header_list}{os.linesep}"
             custom_printout += f"{content_list}"
diff --git a/src/tmtccmd/tm/service_23_file_mgmt.py b/src/tmtccmd/tm/service_23_file_mgmt.py
index ff5c8951..e055fb61 100644
--- a/src/tmtccmd/tm/service_23_file_mgmt.py
+++ b/src/tmtccmd/tm/service_23_file_mgmt.py
@@ -2,7 +2,8 @@
 import struct
 
 from tmtccmd.pus.service_list import PusServices
-from tmtccmd.ecss.tm import PusTelemetry, PusTmBase, PusTmInfoBase, CdsShortTimestamp, PusVersion
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.utility.logger import get_console_logger
 
 LOGGER = get_console_logger()
diff --git a/src/tmtccmd/tm/service_2_raw_cmd.py b/src/tmtccmd/tm/service_2_raw_cmd.py
index 53e4feee..b2a6595e 100644
--- a/src/tmtccmd/tm/service_2_raw_cmd.py
+++ b/src/tmtccmd/tm/service_2_raw_cmd.py
@@ -1,7 +1,8 @@
 """Base class for implementation of PUS Service 2 handling.
 """
 from __future__ import annotations
-from tmtccmd.ecss.tm import PusTmInfoBase, PusTmBase, CdsShortTimestamp, PusVersion, PusTelemetry
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 
 
 class Service2TM(PusTmInfoBase, PusTmBase):
diff --git a/src/tmtccmd/tm/service_3_base.py b/src/tmtccmd/tm/service_3_base.py
index 7e098142..361590f2 100644
--- a/src/tmtccmd/tm/service_3_base.py
+++ b/src/tmtccmd/tm/service_3_base.py
@@ -2,7 +2,6 @@
 import enum
 
 from tmtccmd.pus import ObjectId
-from tmtccmd.ecss.tm import PusTelemetry
 
 
 class HkContentType(enum.Enum):
diff --git a/src/tmtccmd/tm/service_3_housekeeping.py b/src/tmtccmd/tm/service_3_housekeeping.py
index 6c6cb89d..87189455 100644
--- a/src/tmtccmd/tm/service_3_housekeeping.py
+++ b/src/tmtccmd/tm/service_3_housekeeping.py
@@ -5,11 +5,11 @@
 from abc import abstractmethod
 import struct
 
-from tmtccmd.pus import ObjectId
-from tmtccmd.ecss.tm import PusTelemetry, PusTmInfoBase, PusTmBase, CdsShortTimestamp, PusVersion
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.tm import Service3Base
 from tmtccmd.utility.logger import get_console_logger
-from typing import Type, Tuple, List
+from typing import Tuple, List
 
 
 LOGGER = get_console_logger()
diff --git a/src/tmtccmd/tm/service_5_event.py b/src/tmtccmd/tm/service_5_event.py
index 343a5b52..d30287f6 100644
--- a/src/tmtccmd/tm/service_5_event.py
+++ b/src/tmtccmd/tm/service_5_event.py
@@ -6,7 +6,8 @@
 import struct
 
 from tmtccmd.pus.service_list import PusServices
-from tmtccmd.ecss.tm import PusTelemetry, PusVersion, CdsShortTimestamp, PusTmInfoBase, PusTmBase
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.pus.service_5_event import Srv5Subservices, Srv5Severity
 from tmtccmd.pus.obj_id import ObjectId
 from tmtccmd.utility.logger import get_console_logger
diff --git a/src/tmtccmd/tm/service_8_functional_cmd.py b/src/tmtccmd/tm/service_8_functional_cmd.py
index 7588fee6..ee2f54e1 100644
--- a/src/tmtccmd/tm/service_8_functional_cmd.py
+++ b/src/tmtccmd/tm/service_8_functional_cmd.py
@@ -3,7 +3,8 @@
 from __future__ import annotations
 import struct
 
-from tmtccmd.ecss.tm import PusTelemetry, CdsShortTimestamp, PusTmInfoBase, PusTmBase, PusVersion
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 from tmtccmd.pus import ObjectId
 from tmtccmd.utility.logger import get_console_logger
 
@@ -28,7 +29,7 @@ def __init__(
         self._action_id = action_id
         self._custom_data = custom_data
         source_data = bytearray()
-        source_data.extend(self._object_id.as_bytes())
+        source_data.extend(object_id)
         source_data.extend(struct.pack('!I', self._action_id))
         source_data.extend(self._custom_data)
         pus_tm = PusTelemetry(
@@ -58,8 +59,7 @@ def __init_without_base(instance: Service8TM):
                 LOGGER.warning(f'Length of Service 8 TM data field {len(tm_data)} short than 8')
                 raise ValueError
             instance.specify_packet_info("Functional Data Reply")
-            instance._object_id_bytes = tm_data[0:4]
-            instance._object_id = struct.unpack('!I', instance._object_id_bytes)[0]
+            instance._object_id = ObjectId.from_bytes(obj_id_as_bytes=tm_data[0:4])
             instance._action_id = struct.unpack('!I', tm_data[4:8])[0]
             instance._custom_data = tm_data[8:]
         else:
diff --git a/src/tmtccmd/utility/tmtc_printer.py b/src/tmtccmd/utility/tmtc_printer.py
index 6671b4a6..62a24cb0 100644
--- a/src/tmtccmd/utility/tmtc_printer.py
+++ b/src/tmtccmd/utility/tmtc_printer.py
@@ -4,7 +4,7 @@
 import enum
 from typing import cast
 
-from tmtccmd.ecss.tc import PusTelecommand
+from spacepackets.ecss.tc import PusTelecommand
 from tmtccmd.tm import Service8TM, Service5TM
 from tmtccmd.pus.service_list import PusServices
 from tmtccmd.tm.base import PusTmInfoInterface, PusTmInterface
@@ -170,7 +170,7 @@ def handle_service_8_packet(self, packet_if: PusTmInterface):
             custom_data=srv8_packet.get_custom_data()
         )
         obj_id_dict = hook_obj.get_object_ids()
-        rep_str = obj_id_dict.get(obj_id)
+        rep_str = obj_id_dict.get(bytes(obj_id))
         if rep_str is None:
             rep_str = "unknown object"
         print_string = \


Test patch:
diff --git a/src/tests/test_printer.py b/src/tests/test_printer.py
index 5cb889ad..86e034e9 100644
--- a/src/tests/test_printer.py
+++ b/src/tests/test_printer.py
@@ -1,13 +1,15 @@
 from unittest import TestCase
 
 from tmtccmd.runner import initialize_tmtc_commander
-from tmtccmd.tm import Service1TM, Service5TM, Srv5Subservices, CdsShortTimestamp
+from tmtccmd.tm import Service1TM, Service5TM
+from tmtccmd.tm.service_5_event import Srv5Subservices
+from spacepackets.ccsds.time import CdsShortTimestamp
 from tmtccmd.tc.service_17_test import pack_service17_ping_command
 from tmtccmd.utility.tmtc_printer import TmTcPrinter, DisplayMode
 from tmtccmd.utility.logger import get_console_logger, set_tmtc_console_logger
 from tmtccmd.config.globals import update_global, CoreGlobalIds
 
-from .hook_obj_mock import create_hook_mock_with_srv_handlers
+from tests.hook_obj_mock import create_hook_mock_with_srv_handlers
 
 
 class TestPrinter(TestCase):
diff --git a/src/tests/test_pus.py b/src/tests/test_pus.py
index 61bc0531..31a48886 100755
--- a/src/tests/test_pus.py
+++ b/src/tests/test_pus.py
@@ -1,14 +1,10 @@
 #!/usr/bin/env python3
-import unittest
-
 from unittest import TestCase
-from crcmod import crcmod
 
-from tmtccmd.ecss.tc import PusTelecommand
-from tmtccmd.ecss.tc import generate_crc, generate_packet_crc
-from tmtccmd.ccsds.spacepacket import get_space_packet_sequence_control
-from tmtccmd.ecss.conf import set_default_apid, get_default_apid, PusVersion, get_pus_tm_version
-from tmtccmd.ccsds.time import CdsShortTimestamp
+from spacepackets.ccsds.spacepacket import get_space_packet_sequence_control
+from spacepackets.ccsds.time import CdsShortTimestamp
+from spacepackets.ecss.conf import get_pus_tm_version, PusVersion
+
 from tmtccmd.tm.service_17_test import Service17TM
 
 
@@ -65,69 +61,3 @@ def test_list_functionality(self):
 
         self.assertTrue(header_list != [])
         self.assertTrue(content_list != [])
-
-
-class TestTelecommand(TestCase):
-
-    def test_generic(self):
-        pus_17_telecommand = PusTelecommand(service=17, subservice=1, ssc=25)
-        pus_17_telecommand.print()
-        self.assertTrue(pus_17_telecommand.get_total_length() == len(pus_17_telecommand.pack()))
-        command_tuple = pus_17_telecommand.pack_command_tuple()
-        self.assertTrue(len(command_tuple[0]) == pus_17_telecommand.get_total_length())
-        print(repr(pus_17_telecommand))
-        print(pus_17_telecommand)
-        self.assertTrue(pus_17_telecommand.get_packet_id() == (0x18 << 8 | 0xef))
-        self.assertTrue(pus_17_telecommand.get_app_data() == bytearray())
-        self.assertTrue(pus_17_telecommand.get_apid() == get_default_apid())
-
-        set_default_apid(42)
-        self.assertTrue(get_default_apid() == 42)
-
-        test_app_data = bytearray([1, 2, 3])
-        pus_17_telecommand_with_app_data = PusTelecommand(
-            service=17, subservice=32, ssc=52, app_data=test_app_data
-        )
-
-        self.assertTrue(len(pus_17_telecommand_with_app_data.get_app_data()) == 3)
-        self.assertTrue(pus_17_telecommand_with_app_data.get_app_data() == bytearray([1, 2, 3]))
-
-        pus_17_telecommand_invalid = PusTelecommand(service=493, subservice=5252, ssc=99432942)
-        self.assertTrue(pus_17_telecommand_invalid.get_service() == 0)
-        self.assertTrue(pus_17_telecommand_invalid.get_subservice() == 0)
-        self.assertTrue(pus_17_telecommand_invalid.get_ssc() == 0)
-
-        invalid_input = "hello"
-        self.assertTrue(pus_17_telecommand_invalid.get_data_length(
-            app_data_len=invalid_input, secondary_header_len=0) == 0
-        )
-        self.assertRaises(TypeError, pus_17_telecommand_invalid.get_data_length(
-            app_data_len=invalid_input, secondary_header_len=0)
-        )
-
-    def test_crc_16(self):
-        pus_17_telecommand = PusTelecommand(service=17, subservice=1, ssc=25)
-        crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-        crc = crc_func(pus_17_telecommand.pack())
-        self.assertTrue(crc == 0)
-
-        test_data = bytearray([192, 23, 4, 82, 3, 6])
-        data_with_crc = generate_crc(test_data)
-        crc = crc_func(data_with_crc)
-        self.assertTrue(crc == 0)
-
-        packet_raw = pus_17_telecommand.pack()
-        packet_raw[len(packet_raw) - 1] += 1
-        self.assertTrue(crc_func(packet_raw) != 0)
-        packet_raw = generate_packet_crc(packet_raw)
-        self.assertTrue(crc_func(packet_raw) == 0)
-
-    def test_getter_functions(self):
-        pus_17_telecommand = PusTelecommand(service=17, subservice=1, ssc=25)
-        self.assertTrue(pus_17_telecommand.get_ssc() == 25)
-        self.assertTrue(pus_17_telecommand.get_service() == 17)
-        self.assertTrue(pus_17_telecommand.get_subservice() == 1)
-
-
-if __name__ == '__main__':
-    unittest.main()
diff --git a/src/tests/test_runner.py b/src/tests/test_runner.py
index bfb23b5b..ca23ae2f 100644
--- a/src/tests/test_runner.py
+++ b/src/tests/test_runner.py
@@ -2,8 +2,8 @@
 from tmtccmd.ccsds.handler import CcsdsTmHandler
 from tmtccmd.runner import run_tmtc_commander, initialize_tmtc_commander, get_default_tmtc_backend
 
-from .backend_mock import create_backend_mock, create_frontend_mock
-from .hook_obj_mock import create_hook_mock
+from tests.backend_mock import create_backend_mock, create_frontend_mock
+from tests.hook_obj_mock import create_hook_mock
 
 
 class TestTmtcRunner(TestCase):
diff --git a/src/tmtccmd/tm/service_17_test.py b/src/tmtccmd/tm/service_17_test.py
index 2ff97e9a..24aacd13 100644
--- a/src/tmtccmd/tm/service_17_test.py
+++ b/src/tmtccmd/tm/service_17_test.py
@@ -1,6 +1,7 @@
 from __future__ import annotations
 from tmtccmd.pus.service_list import PusServices
-from tmtccmd.ecss.tm import PusTelemetry, PusTmBase, PusTmInfoBase, PusVersion, CdsShortTimestamp
+from spacepackets.ecss.tm import CdsShortTimestamp, PusVersion, PusTelemetry
+from tmtccmd.tm.base import PusTmInfoBase, PusTmBase
 
 
 class Service17TM(PusTmBase, PusTmInfoBase):