From aea6852d0e9a890c5b4fa3fcbb57fdb416789c9d Mon Sep 17 00:00:00 2001
From: "Robin.Mueller" <robin.mueller.m@gmail.com>
Date: Sun, 26 Apr 2020 19:15:45 +0200
Subject: [PATCH] tm generator working, logger working

---
 comIF/obsw_dummy_com_if.py                  |   2 -
 comIF/obsw_serial_com_if.py                 |   2 +-
 sendreceive/obsw_command_sender_receiver.py |  16 +--
 sendreceive/obsw_tm_listener.py             |  12 ++-
 tm/obsw_pus_tm_base.py                      | 106 ++++++++++++--------
 tm/obsw_pus_tm_creator.py                   |  21 ++--
 tm/obsw_pus_tm_factory.py                   |   6 +-
 tm/obsw_tm_service_1.py                     |   2 +-
 utility/obsw_tmtc_printer.py                |   7 +-
 9 files changed, 99 insertions(+), 75 deletions(-)

diff --git a/comIF/obsw_dummy_com_if.py b/comIF/obsw_dummy_com_if.py
index ddc36f8..6730a5b 100644
--- a/comIF/obsw_dummy_com_if.py
+++ b/comIF/obsw_dummy_com_if.py
@@ -39,8 +39,6 @@ class DummyComIF(CommunicationInterface):
             return [tm_packet]
         return []
 
-
-
     def send_telecommand(self, tc_packet: PusTelecommand, tc_packet_info: PusTcInfoT = None) -> None:
         if isinstance(tc_packet_info, dict) and tc_packet_info.__len__() > 0:
             self.service_sent = tc_packet_info[TcDictionaryKeys.SERVICE]
diff --git a/comIF/obsw_serial_com_if.py b/comIF/obsw_serial_com_if.py
index c718b5d..14617c5 100644
--- a/comIF/obsw_serial_com_if.py
+++ b/comIF/obsw_serial_com_if.py
@@ -50,7 +50,7 @@ class SerialComIF(CommunicationInterface):
         # self.tmtc_printer.print_telecommand(tc_packet, tc_packet_info)
         self.serial.write(tc_packet)
 
-    def receive_telemetry(self, parameters: any = 0) -> list:
+    def receive_telemetry(self, parameters: any = 0) -> PusTmListT:
         (packet_received, packet_list) = self.poll_interface()
         if packet_received:
             return packet_list
diff --git a/sendreceive/obsw_command_sender_receiver.py b/sendreceive/obsw_command_sender_receiver.py
index d800fd7..8824782 100644
--- a/sendreceive/obsw_command_sender_receiver.py
+++ b/sendreceive/obsw_command_sender_receiver.py
@@ -11,8 +11,8 @@ if the first reply has not been received.
 
 @author: R. Mueller
 """
-import sys
 import time
+import logging
 
 import config.obsw_config as g
 from comIF.obsw_com_interface import CommunicationInterface
@@ -21,7 +21,7 @@ from sendreceive.obsw_tm_listener import TmListener
 from tc.obsw_pus_tc_base import TcQueueEntryT
 from tm.obsw_pus_tm_factory import PusTmQueueT
 from utility.obsw_logger import get_logger
-from tm.obsw_pus_tm_factory import PusTelemetryFactory
+
 logger = get_logger()
 
 
@@ -150,7 +150,11 @@ class CommandSenderReceiver:
         time.sleep(0.5)
 
     def print_tm_queue(self, tm_queue: PusTmQueueT):
-        for tm_packet in tm_queue:
-            logger.debug(str(tm_packet))
-            tm_info = tm_packet.pack_tm_information()
-            self._tmtc_printer.print_telemetry(tm_packet, tm_info)
+        for tm_packet_list in tm_queue:
+            try:
+                for tm_packet in tm_packet_list:
+                    self._tmtc_printer.print_telemetry(tm_packet)
+            except AttributeError as e:
+                logger.exception(
+                    "CommandSenderReceiver Exception: Invalid queue entry. Traceback:", e)
+
diff --git a/sendreceive/obsw_tm_listener.py b/sendreceive/obsw_tm_listener.py
index f017770..2020545 100644
--- a/sendreceive/obsw_tm_listener.py
+++ b/sendreceive/obsw_tm_listener.py
@@ -80,7 +80,7 @@ class TmListener:
             while not self.mode_op_finished.is_set():
                 self.perform_mode_operation()
             self.mode_op_finished.clear()
-            logger.info("Transitioning to listener mode.")
+            logger.info("TmListener: Transitioning to listener mode.")
             self.mode_id = g.ModeList.ListenerMode
 
     def perform_mode_operation(self):
@@ -137,15 +137,17 @@ class TmListener:
             logger.error("TmListener: Configuration error in communication interface!")
             sys.exit()
 
-    def retrieve_tm_packet_queue(self):
+    def retrieve_tm_packet_queue(self) -> PusTmQueueT:
         return self.__tm_packet_queue.copy()
 
     @staticmethod
-    def retrieve_info_queue_from_packet_queue(tm_queue: PusTmQueueT, pus_info_queue_to_fill: PusTmInfoQueueT):
+    def retrieve_info_queue_from_packet_queue(
+            tm_queue: PusTmQueueT, pus_info_queue_to_fill: PusTmInfoQueueT):
         tm_queue_copy = tm_queue.copy()
         while tm_queue_copy.__len__() != 0:
-            pus_packet = tm_queue_copy.pop()
-            pus_info_queue_to_fill.append(pus_packet.pack_tm_information())
+            pus_packet_list = tm_queue_copy.pop()
+            for pus_packet in pus_packet_list:
+                pus_info_queue_to_fill.append(pus_packet.pack_tm_information())
 
     def clear_tm_packet_queue(self):
         self.__tm_packet_queue.clear()
diff --git a/tm/obsw_pus_tm_base.py b/tm/obsw_pus_tm_base.py
index 6916758..609b447 100644
--- a/tm/obsw_pus_tm_base.py
+++ b/tm/obsw_pus_tm_base.py
@@ -41,17 +41,25 @@ class PusTelemetry:
     PUS Telemetry structure according to ECSS-E-70-41A p.46. Also see structure below (bottom).
     """
     PUS_HEADER_SIZE = 6
-    def __init__(self, byte_array: bytearray = bytearray()):
-        if byte_array == bytearray():
+    CDS_SHORT_SIZE = 7
+    PUS_TIMESTAMP_SIZE = CDS_SHORT_SIZE
+    def __init__(self, raw_telemetry: bytearray = bytearray()):
+        if raw_telemetry == bytearray():
             return
-        self._packet_raw: Final = byte_array
-        self._pus_header: Final = PusPacketHeader(byte_array)
-        byte_array = byte_array[6:]
-        self._data_field_header: Final = PusPacketDataFieldHeader(byte_array)
-        byte_array = byte_array[12:]
-        self._tm_data: Final = byte_array[:len(byte_array) - 2]
-        self._crc: Final = byte_array[len(byte_array) - 2] << 8 | byte_array[len(byte_array) - 1]
+        self._packet_raw: Final = raw_telemetry
+        self._pus_header: Final = PusPacketHeader(raw_telemetry)
+        self._valid = False
+        if self._pus_header.length + PusTelemetry.PUS_HEADER_SIZE + 1 > len(raw_telemetry):
+            logger.error("PusTelemetry: Passed packet shorter than specified packet "
+                         "length in PUS header")
+            return
+        self._data_field_header: Final = PusPacketDataFieldHeader(raw_telemetry[6:])
+        self._tm_data: Final = raw_telemetry[PusPacketDataFieldHeader.DATA_HEADER_SIZE +
+                                             PusTelemetry.PUS_HEADER_SIZE:len(raw_telemetry) - 2]
+        self._crc: Final = raw_telemetry[len(raw_telemetry) - 2] << 8 | \
+                           raw_telemetry[len(raw_telemetry) - 1]
         self.print_info = ""
+        self.__perform_crc_check(raw_telemetry)
 
     def get_service(self):
         """
@@ -65,6 +73,9 @@ class PusTelemetry:
         """
         return self._data_field_header.service_subtype
 
+    def is_valid(self):
+        return self._valid
+
     def get_tm_data(self) -> bytearray:
         """
         :return: TM application data (raw)
@@ -82,10 +93,22 @@ class PusTelemetry:
             TmDictionaryKeys.SSC: self.get_ssc(),
             TmDictionaryKeys.DATA: self._tm_data,
             TmDictionaryKeys.CRC: self._crc,
-            TmDictionaryKeys.VALID: self._pus_header.valid
+            TmDictionaryKeys.VALID: self._valid
         }
         return tm_information
 
+    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("PusPacketHeader: 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("PusPacketHeader: Invalid CRC detected !")
+
     def specify_packet_info(self, print_info: str):
         """
         Caches a print information string for later printing
@@ -112,6 +135,10 @@ class PusTelemetry:
         """
         self._data_field_header.append_data_field_header(content_list)
         self._pus_header.append_pus_packet_header(content_list)
+        if self.is_valid():
+            content_list.append("Yes")
+        else:
+            content_list.append("No")
 
     def append_telemetry_column_headers(self, header_list: list):
         """
@@ -124,6 +151,7 @@ class PusTelemetry:
         """
         self._data_field_header.append_data_field_header_column_header(header_list)
         self._pus_header.append_pus_packet_header_column_headers(header_list)
+        header_list.append("Packet valid")
 
     def get_raw_packet(self) -> bytes:
         """
@@ -147,26 +175,37 @@ class PusTelemetry:
         """
         return self._pus_header.source_sequence_count
 
-    def return_data_string(self) -> str:
+    def print_full_packet_string(self):
+        """
+        Print the full TM packet in a clean format.
+        """
+
+        logger.info(self.return_data_string(self._packet_raw, len(self._packet_raw)))
+
+    def print_source_data(self):
+        """
+        Prints the TM source data in a clean format
+        :return:
+        """
+        logger.info(self.return_data_string(self._tm_data, len(self._tm_data)))
+
+    @staticmethod
+    def return_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 byte in self._tm_data:
-            str_to_print += str(hex(byte)) + " , "
+        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
 
-    def print_data(self):
-        """
-        Prints the TM data in a clean format
-        :return:
-        """
-        print(self.return_data_string())
-
 
 # pylint: disable=too-many-instance-attributes
 class PusPacketHeader:
@@ -175,8 +214,8 @@ class PusPacketHeader:
     """
 
     def __init__(self, pus_packet_raw: bytes):
-        data_to_check = pus_packet_raw
         if len(pus_packet_raw) < PusTelemetry.PUS_HEADER_SIZE:
+            logger.warning("PusPacketHeader: Packet size smaller than PUS header size!")
             self.version = 0
             self.type = 0
             self.data_field_header_flag = 0
@@ -184,7 +223,6 @@ class PusPacketHeader:
             self.segmentation_flag = 0
             self.source_sequence_count = 0
             self.length = 0
-            self.valid = False
             return
         self.version = pus_packet_raw[0] >> 5
         self.type = pus_packet_raw[0] & 0x10
@@ -193,38 +231,23 @@ class PusPacketHeader:
         self.segmentation_flag = (pus_packet_raw[2] & 0xC0) >> 6
         self.source_sequence_count = ((pus_packet_raw[2] & 0x3F) << 8) | pus_packet_raw[3]
         self.length = pus_packet_raw[4] << 8 | pus_packet_raw[5]
-        self.valid = False
-        crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000)
-        if len(data_to_check) < ((self.length + 1) + PusTelemetry.PUS_HEADER_SIZE):
-            logger.warning("PusPacketHeader: Invalid packet length")
-            return
-        data_to_check = data_to_check[0:(self.length + 1) + PusTelemetry.PUS_HEADER_SIZE]
-        crc = crc_func(data_to_check)
-        if crc == 0:
-            self.valid = True
-        else:
-            logger.warning("PusPacketHeader: Invalid CRC detected !")
 
     def append_pus_packet_header(self, array):
         array.append(str(chr(self.apid)))
         array.append(str(self.source_sequence_count))
-        if self.valid:
-            array.append("Yes")
-        else:
-            array.append("No")
 
     @staticmethod
     def append_pus_packet_header_column_headers(array):
         array.append("APID")
         array.append("SSC")
-        array.append("Packet Valid")
 
 
 class PusPacketDataFieldHeader:
     """
     Unpacks the PUS packet data field header.
     """
-    def __init__(self, bytes_array):
+    DATA_HEADER_SIZE = PusTelemetry.PUS_TIMESTAMP_SIZE + 4
+    def __init__(self, bytes_array: bytearray):
         self.pus_version_and_ack_byte = (bytes_array[0] & 0x70) >> 4
         self.service_type = bytes_array[1]
         self.service_subtype = bytes_array[2]
@@ -254,6 +277,7 @@ class PusPacketDataFieldHeader:
         self.time.print_time_headers(header_list)
 
 
+
 class PusTelemetryTimestamp:
     """
     Unpacks the time datafield of the TM packet. Right now, CDS Short timeformat is used,
@@ -263,6 +287,7 @@ class PusTelemetryTimestamp:
     SECONDS_PER_DAY = 86400
     EPOCH = datetime.datetime.utcfromtimestamp(0)
     DAYS_CCSDS_TO_UNIX = 4383
+    TIMESTAMP_SIZE = PusTelemetry.PUS_TIMESTAMP_SIZE
     def __init__(self, byte_array: bytearray=bytearray([])):
         if len(byte_array) > 0:
             # pField = byte_array[0]
@@ -276,7 +301,8 @@ class PusTelemetryTimestamp:
             self.datetime = str(datetime.datetime.
                             utcfromtimestamp(self.time).strftime("%Y-%m-%d %H:%M:%S.%f"))
 
-    def pack_current_time(self) -> bytearray:
+    @staticmethod
+    def pack_current_time() -> bytearray:
         """
         Returns a seven byte CDS short timestamp
         """
diff --git a/tm/obsw_pus_tm_creator.py b/tm/obsw_pus_tm_creator.py
index fad4301..1f768b2 100644
--- a/tm/obsw_pus_tm_creator.py
+++ b/tm/obsw_pus_tm_creator.py
@@ -47,38 +47,31 @@ class PusTelemetryCreator(PusTelemetry):
         source_length = self.get_source_data_length()
         tm_packet_raw.append((source_length & 0xFF00) >> 8)
         tm_packet_raw.append(source_length & 0xFF)
-        logger.debug(len(tm_packet_raw))
         # PUS Source Data Field
         tm_packet_raw.append(self.data_field_version)
         tm_packet_raw.append(self.service)
         tm_packet_raw.append(self.subservice)
         tm_packet_raw.append(self.pack_subcounter)
-        logger.debug(len(tm_packet_raw))
-        timestamper = PusTelemetryTimestamp()
-        tm_packet_raw.extend(timestamper.pack_current_time())
-        logger.debug(len(tm_packet_raw))
-
+        tm_packet_raw.extend(PusTelemetryTimestamp.pack_current_time())
         # Source Data
         tm_packet_raw.extend(self.source_data)
-        logger.debug(len(tm_packet_raw))
-
         # 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)
-        logger.debug(len(tm_packet_raw))
         return tm_packet_raw
 
     def get_source_data_length(self) -> 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
+        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:
-            data_length = 4 + len(self.source_data) + 1
+            data_length = 4  + PusTelemetry.PUS_TIMESTAMP_SIZE + len(self.source_data) + 1
             return data_length
         except TypeError:
             logger.error("PusTelecommand: Invalid type of application data!")
diff --git a/tm/obsw_pus_tm_factory.py b/tm/obsw_pus_tm_factory.py
index 5e99f6a..f6b9be1 100644
--- a/tm/obsw_pus_tm_factory.py
+++ b/tm/obsw_pus_tm_factory.py
@@ -10,9 +10,11 @@ import struct
 logger = get_logger()
 PusRawTmList = List[bytearray]
 PusRawTmQueue = Deque[bytearray]
-PusTmQueueT = Deque[PusTelemetry]
-PusTmListT = List[PusTelemetry]
 PusTmTupleT = Tuple[PusTmInfoT, PusTelemetry]
+
+PusTmListT = List[PusTelemetry]
+PusTmQueueT = Deque[PusTmListT]
+
 PusTmInfoQueueT = Deque[PusTmInfoT]
 PusTmTupleQueueT = Deque[PusTmTupleT]
 
diff --git a/tm/obsw_tm_service_1.py b/tm/obsw_tm_service_1.py
index c790828..952e631 100644
--- a/tm/obsw_tm_service_1.py
+++ b/tm/obsw_tm_service_1.py
@@ -36,7 +36,7 @@ class Service1TM(PusTelemetry):
                 self.errorParam1 = struct.unpack('>I', self._tm_data[7:11])[0]
                 self.errorParam2 = struct.unpack('>I', self._tm_data[11:15])[0]
             else:
-                self.print_data()
+                self.print_source_data()
                 self.err_code = struct.unpack('>H', self._tm_data[4:6])[0]
                 self.errorParam1 = struct.unpack('>I', self._tm_data[6:10])[0]
                 self.errorParam2 = struct.unpack('>I', self._tm_data[10:14])[0]
diff --git a/utility/obsw_tmtc_printer.py b/utility/obsw_tmtc_printer.py
index 6e8a972..7b0117e 100644
--- a/utility/obsw_tmtc_printer.py
+++ b/utility/obsw_tmtc_printer.py
@@ -11,7 +11,6 @@
 import os
 import sys
 import enum
-import logging
 from config import obsw_config as g
 from tm.obsw_pus_tm_base import PusTelemetry
 from tm.obsw_tm_service_3 import Service3TM
@@ -78,7 +77,7 @@ class TmTcPrinter:
 
     def __handle_long_print(self, tm_packet: PusTelemetry):
         self.print_buffer = "Received Telemetry: " + tm_packet.print_info
-        print(self.print_buffer)
+        logger.info(self.print_buffer)
         self.add_print_buffer_to_file_buffer()
         self.__handle_column_header_print(tm_packet)
         self.__handle_tm_content_print(tm_packet)
@@ -87,7 +86,7 @@ class TmTcPrinter:
         rec_pus = []
         tm_packet.append_telemetry_column_headers(rec_pus)
         self.print_buffer = str(rec_pus)
-        print(self.print_buffer)
+        logger.info(self.print_buffer)
         self.add_print_buffer_to_file_buffer()
 
     def __handle_tm_content_print(self, tm_packet: PusTelemetry):
@@ -98,7 +97,7 @@ class TmTcPrinter:
         rec_pus = []
         tm_packet.append_telemetry_content(rec_pus)
         self.print_buffer = str(rec_pus)
-        print(self.print_buffer)
+        logger.info(self.print_buffer)
         self.add_print_buffer_to_file_buffer()
 
     def __handle_hk_print(self, tm_packet: Service3TM):
-- 
GitLab