diff --git a/comIF/obsw_com_config.py b/comIF/obsw_com_config.py index c50524a8997cb085db1dede620f21e535ca5b775..534a2360483b22d193853c31f8612c6ffc75b108 100644 --- a/comIF/obsw_com_config.py +++ b/comIF/obsw_com_config.py @@ -37,8 +37,8 @@ def set_communication_interface(tmtc_printer: TmTcPrinter) -> CommunicationInter serial_timeout=serial_timeout) elif g.G_COM_IF == g.ComIF.QEMU: communication_interface = QEMUComIF( - tmtcPrinter=tmtc_printer, tmTimeout=g.G_TM_TIMEOUT, - tcTimeoutFactor=g.G_TC_SEND_TIMEOUT_FACTOR) + tmtc_printer=tmtc_printer, tm_timeout=g.G_TM_TIMEOUT, + tc_timeout_factor=g.G_TC_SEND_TIMEOUT_FACTOR) else: communication_interface = DummyComIF(tmtc_printer=tmtc_printer) return communication_interface diff --git a/comIF/obsw_dummy_com_if.py b/comIF/obsw_dummy_com_if.py index 20c20f928890f1c6d86596bbd9026ac021194ed9..3a9e56438ba589c73089e460d1ac6d7342b2b084 100644 --- a/comIF/obsw_dummy_com_if.py +++ b/comIF/obsw_dummy_com_if.py @@ -11,6 +11,9 @@ from comIF.obsw_com_interface import CommunicationInterface from tc.obsw_pus_tc_base import PusTelecommand, PusTcInfoT, TcDictionaryKeys from tm.obsw_pus_tm_factory import PusTelemetryFactory from tm.obsw_tm_service_1 import Service1TmPacked +from utility.obsw_logger import get_logger + +LOGGER = get_logger() class DummyComIF(CommunicationInterface): @@ -34,8 +37,8 @@ class DummyComIF(CommunicationInterface): pass def receive_telemetry(self, parameters: any = 0): - if self.service_sent == 17 or self.service_sent == 5 and self.reply_pending: - tm_list = [] + if (self.service_sent == 17 or self.service_sent == 5) and self.reply_pending: + LOGGER.debug("receive crap called") tm_packer = Service1TmPacked(subservice=1, ssc=self.ssc, tc_packet_id=self.tc_packet_id, tc_ssc=self.tc_ssc) @@ -49,8 +52,7 @@ class DummyComIF(CommunicationInterface): tm_list.append(tm_packet) self.reply_pending = False self.ssc += 1 - return tm_list - return [] + return tm_list 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: diff --git a/comIF/obsw_qemu_com_if.py b/comIF/obsw_qemu_com_if.py index 50c4287d653e9b5fc616a78a9dff66c0c3b6d946..8cb397ee650911fe2e9a4ab8254a5815041e0a9a 100755 --- a/comIF/obsw_qemu_com_if.py +++ b/comIF/obsw_qemu_com_if.py @@ -55,13 +55,14 @@ def start_background_loop(loop: asyncio.AbstractEventLoop) -> None: class QEMUComIF(CommunicationInterface): - def __init__(self, tmtcPrinter, tmTimeout, tcTimeoutFactor): - super().__init__(tmtcPrinter) - self.tmTimeout = tmTimeout - self.tcTimeoutFactor = tcTimeoutFactor + def __init__(self, tmtc_printer, tm_timeout, tc_timeout_factor): + super().__init__(tmtc_printer) + self.tmTimeout = tm_timeout + self.tcTimeoutFactor = tc_timeout_factor self.loop = asyncio.get_event_loop() self.number_of_packets = 0 - if(not self.loop.is_running()): + self.data = [] + if not self.loop.is_running(): self.t = Thread(target=start_background_loop, args=(self.loop,), daemon=True) self.t.start() @@ -76,26 +77,25 @@ class QEMUComIF(CommunicationInterface): def send_telecommand(self, tcPacket, tcPacketInfo=""): asyncio.run_coroutine_threadsafe( - self.sendTelecommandAsync(tcPacket, tcPacketInfo), self.loop).result() + self.send_telecommand_async(tcPacket, tcPacketInfo), self.loop).result() - async def sendTelecommandAsync(self, tcPacket, tcPacketInfo): - self.tmtc_printer.print_telecommand(tcPacket, tcPacketInfo) - await self.usart.write(tcPacket) + async def send_telecommand_async(self, tc_packet, tcPacketInfo): + self.tmtc_printer.print_telecommand(tc_packet, tcPacketInfo) + await self.usart.write(tc_packet) self.usart.inject_timeout_error() def receive_telemetry(self, parameters=0): - packetList = self.poll_interface() - return packetList + packet_list = self.poll_interface() + return packet_list def poll_interface(self, parameter=0): + packet_list = [] if self.data_available(): - pusDataList, numberOfPackets = self.pollPusPackets() - packetList = [] - for counter in range(0, numberOfPackets): - packet = PusTelemetryFactory.create(pusDataList[counter]) - # self.tmtc_printer.print_telemetry(packet) - packetList.append(packet) - return packetList + pus_data_list, number_of_packets = self.poll_pus_packets() + for counter in range(0, number_of_packets): + packet = PusTelemetryFactory.create(pus_data_list[counter]) + packet_list.append(packet) + return packet_list def data_available(self, timeout=0): if self.usart.newDataAvailable(): @@ -109,11 +109,11 @@ class QEMUComIF(CommunicationInterface): elapsed_time = time.time() - start_time return False - def pollPusPackets(self): - packets = self.pollPusPacketsAsync() + def poll_pus_packets(self): + packets = self.poll_pus_packets_async() return packets - def pollPusPacketsAsync(self): + def poll_pus_packets_async(self): pus_data_list = [] self.data = self.usart.read(256) payload_length = (self.data[4] << 8 | self.data[5]) @@ -152,20 +152,6 @@ class QEMUComIF(CommunicationInterface): self.number_of_packets = self.number_of_packets + 1 return end_index - def performListenerMode(self): - print("Listening for packages ...") - while True: - self.pollInterface() - - def receiveTelemetryAndStoreIntoQueue(self, tmQueue): - packet = self.pollInterface() - tmQueue.put(packet) - - def receiveTelemetryAndStoreTuple(self, tmTupleQueue): - packet = self.pollInterface() - tmInfo = packet.packTmInformation() - tmTupleQueue.put(packet, tmInfo) - class QmpException(Exception): """An exception caused by the QML/QEMU as response to a failed command""" diff --git a/comIF/obsw_serial_com_if.py b/comIF/obsw_serial_com_if.py index c63152194e1aefd3c3601d1dbe3853fa87c505a3..c7f45715ab3245536afbb915e55f9e10ef2e8b6a 100644 --- a/comIF/obsw_serial_com_if.py +++ b/comIF/obsw_serial_com_if.py @@ -117,3 +117,19 @@ class SerialComIF(CommunicationInterface): self.number_of_packets = self.number_of_packets + 1 return end_index + # def receive_telemetry_and_store_tm(self, tm_queue: PusTmQueueT) -> Union[None, PusTmQueueT]: + # (packet_received, pus_packets) = self.poll_interface() + # if packet_received: + # for packet in pus_packets: + # tm_queue.append(packet) + # return tm_queue + # + # def receive_telemetry_and_store_info(self, tm_info_queue: PusTmInfoQueueT) -> \ + # Union[None, PusTmInfoQueueT]: + # (packet_received, pus_packets) = self.poll_interface() + # if packet_received: + # for packet in pus_packets: + # tm_info = packet.pack_tm_information() + # tm_info_queue.append(tm_info) + # return tm_info_queue + diff --git a/config/obsw_config.py b/config/obsw_config.py index 3ca8f26d2a4c51b0d8406269353c137c8eacb439..16da60abe9b4704130451954b80407c2cb39be89 100644 --- a/config/obsw_config.py +++ b/config/obsw_config.py @@ -63,7 +63,7 @@ All global variables, set in main program with arg parser # TMTC Client G_TMTC_LOGGER_NAME = "TMTC Logger" G_ERROR_LOG_FILE_NAME = "tmtc_error.log" -G_PP = pprint.PrettyPrinter +G_PP = pprint.PrettyPrinter() # General Settings G_SCRIPT_MODE = 1 diff --git a/sendreceive/obsw_multiple_commands_sender_receiver.py b/sendreceive/obsw_multiple_commands_sender_receiver.py index 7fe0377161b33a3fb1abdb7b86513ca0837f6392..b40d1d6e0631f57d36522d8b2fc25e5690b18045 100644 --- a/sendreceive/obsw_multiple_commands_sender_receiver.py +++ b/sendreceive/obsw_multiple_commands_sender_receiver.py @@ -1,11 +1,8 @@ """ -@file - obsw_config.py -@date - 01.11.2019 -@brief - Used to send multiple TCs as bursts and listen for replies simultaneously. Used by UnitTester +@brief Used to send multiple TCs as bursts and listen for replies simultaneously. + Used by Module Tester """ +import sys import time from typing import Union, Deque from collections import deque @@ -17,7 +14,7 @@ from sendreceive.obsw_tm_listener import TmListenerT import config.obsw_config as g from utility.obsw_tmtc_printer import get_logger -logger = get_logger() +LOGGER = get_logger() class MultipleCommandSenderReceiver(SequentialCommandSenderReceiver): """ @@ -45,7 +42,7 @@ class MultipleCommandSenderReceiver(SequentialCommandSenderReceiver): self.waitIntervals = wait_intervals self.waitTime = wait_time self.printTm = print_tm - self.tmTupleQueue = deque() + self.tm_packet_queue = deque() self.tcInfoQueue = deque() self.pusPacketInfo = [] self.pusPacket = [] @@ -58,15 +55,16 @@ class MultipleCommandSenderReceiver(SequentialCommandSenderReceiver): # TC info queue is set in this function self.__send_all_queue() self.wait_for_last_replies_listening(self._tm_timeout / 1.5) - self.tmTupleQueue = self.__retrieve_listener_tm_tuple() + self.tm_packet_queue = self._tm_listener.retrieve_tm_packet_queue() + self._tm_listener.clear_tm_packet_queue() self._tm_listener.event_mode_op_finished.set() if g.G_PRINT_TO_FILE: self._tmtc_printer.print_to_file() except (KeyboardInterrupt, SystemExit): - logger.info("Closing TMTC Client") - exit() + LOGGER.info("Closing TMTC Client") + sys.exit() - return self.tcInfoQueue, self.tmTupleQueue + return self.tcInfoQueue, self.tm_packet_queue def __handle_tc_resending(self): while not self.__all_replies_received: @@ -95,15 +93,15 @@ class MultipleCommandSenderReceiver(SequentialCommandSenderReceiver): else: time.sleep(self.waitTime) - def __retrieve_listener_tm_tuple(self): + def __retrieve_listener_tm_packet_queue(self): if self._tm_listener.event_reply_received.is_set(): - return self._tm_listener.__tm_info_queue + return self._tm_listener.retrieve_tm_packet_queue() else: - print("Multiple Command SenderReceiver: Configuration error," + LOGGER.error("Multiple Command SenderReceiver: Configuration error," " reply event not set in TM listener") def __clear_listener_tm_info_queue(self): - self._tm_listener.__tm_info_queue.clear() + self._tm_listener.clear_tm_packet_queue() @staticmethod def wait_for_last_replies_listening(wait_time: float): diff --git a/sendreceive/obsw_tm_listener.py b/sendreceive/obsw_tm_listener.py index 0906aaacb5727034621d535911c571eb3dcb1cad..0e13387cb99b67e257a5b06c7087364b987653e7 100644 --- a/sendreceive/obsw_tm_listener.py +++ b/sendreceive/obsw_tm_listener.py @@ -22,7 +22,7 @@ from comIF.obsw_com_interface import CommunicationInterface from tm.obsw_pus_tm_factory import PusTmQueueT, PusTmInfoQueueT import config.obsw_config as g -logger = get_logger() +LOGGER = get_logger() TmListenerT = TypeVar('TmListenerT', bound='TmListener') @@ -80,20 +80,32 @@ class TmListener: time.sleep(1) def default_operation(self): - self.com_interface.poll_interface() + """ + Core function. Normally, polls all packets + """ + self.perform_core_operation() if self.event_mode_change.is_set(): self.event_mode_change.clear() - start_time = time.time() - while not self.event_mode_op_finished.is_set(): - elapsed_time = time.time() - start_time - if elapsed_time < TmListener.MODE_OPERATION_TIMEOUT: - self.perform_mode_operation() + start_time = time.time() + while not self.event_mode_op_finished.is_set(): + elapsed_time = time.time() - start_time + if elapsed_time < TmListener.MODE_OPERATION_TIMEOUT: + self.perform_mode_operation() + else: + LOGGER.warning("TmListener: Mode operation timeout occured!") + break + self.event_mode_op_finished.clear() + LOGGER.info("TmListener: Transitioning to listener mode.") + self.mode_id = g.ModeList.ListenerMode + + def perform_core_operation(self): + packet_list = self.com_interface.receive_telemetry() + if len(packet_list) > 0: + if self.lock_listener.acquire(True, timeout=1): + self.__tm_packet_queue.append(packet_list) else: - logger.warning("TmListener: Mode operation timeout occured!") - break - self.event_mode_op_finished.clear() - logger.info("TmListener: Transitioning to listener mode.") - self.mode_id = g.ModeList.ListenerMode + LOGGER.error("TmListener: Blocked on lock acquisition!") + self.lock_listener.release() def perform_mode_operation(self): """ @@ -103,7 +115,7 @@ class TmListener: """ # Listener Mode if self.mode_id == g.ModeList.ListenerMode: - pass + self.event_mode_op_finished.set() # Single Command Mode elif self.mode_id == g.ModeList.SingleCommandMode: # Listen for one reply sequence. @@ -114,13 +126,12 @@ class TmListener: elif self.mode_id == g.ModeList.ServiceTestMode or \ self.mode_id == g.ModeList.SoftwareTestMode: if self.check_for_one_telemetry_sequence(): - logger.info("TmListener: Reply sequence received!") + LOGGER.info("TmListener: Reply sequence received!") self.event_reply_received.set() elif self.mode_id == g.ModeList.UnitTest: # TODO: needs to be reworked. Info queue is stupid. just pop the normal queue and # pack the information manually - # self.__tm_info_queue = self.com_interface.receive_telemetry_and_store_info(self.__tm_info_queue) - self.event_reply_received.set() + self.perform_core_operation() def check_for_one_telemetry_sequence(self) -> bool: """ @@ -134,26 +145,30 @@ class TmListener: elif tm_ready is True: return self.__read_telemetry_sequence() else: - logger.error("TmListener: Configuration error in communication interface!") + LOGGER.error("TmListener: Configuration error in communication interface!") sys.exit() def __read_telemetry_sequence(self): """ Thread-safe implementation for reading a telemetry sequence. """ - if not self.lock_listener.acquire(True, timeout=1): - logger.error("TmListener: Blocked on lock acquisition!") - self.__tm_packet_queue.append(self.com_interface.receive_telemetry()) + if self.lock_listener.acquire(True, timeout=1): + self.__tm_packet_queue.append(self.com_interface.receive_telemetry()) + else: + LOGGER.error("TmListener: Blocked on lock acquisition for longer than 1 second!") self.lock_listener.release() start_time = time.time() elapsed_time = 0 - logger.info("TmListener: Listening for " + str(self.tm_timeout) + " seconds") + LOGGER.info("TmListener: Listening for " + str(self.tm_timeout) + " seconds") while elapsed_time < self.tm_timeout: tm_ready = self.com_interface.data_available(1.0) if tm_ready: - if not self.lock_listener.acquire(True, timeout=1): - logger.error("TmListener: Blocked on lock acquisition!") - self.__tm_packet_queue.append(self.com_interface.receive_telemetry()) + if self.lock_listener.acquire(True, timeout=1): + tm_list = self.com_interface.receive_telemetry() + self.__tm_packet_queue.append(tm_list) + LOGGER.debug(tm_list) + else: + LOGGER.critical("TmListener: Blocked on lock acquisition for longer than 1 second!") self.lock_listener.release() elapsed_time = time.time() - start_time # the timeout value can be set by special TC queue entries if wiretapping_packet handling @@ -162,11 +177,12 @@ class TmListener: self.tm_timeout = g.G_TM_TIMEOUT return True - # TODO: Not thread-safe, implement lock def retrieve_tm_packet_queue(self) -> PusTmQueueT: - if not self.lock_listener.acquire(True, timeout=1): - logger.error("TmListener: Blocked on lock acquisition!") - tm_queue_copy = self.__tm_packet_queue.copy() + if self.lock_listener.acquire(True, timeout=1): + tm_queue_copy = self.__tm_packet_queue.copy() + else: + tm_queue_copy = self.__tm_packet_queue.copy() + LOGGER.critical("TmListener: Blocked on lock acquisition for longer than 1 second!") self.lock_listener.release() return tm_queue_copy diff --git a/test/obsw_module_test.py b/test/obsw_module_test.py index 3b4a985435754053330ffec3b4055a3227c819b9..4de55c031663a4d53fd7f15bf06eb9a60bef7dea 100644 --- a/test/obsw_module_test.py +++ b/test/obsw_module_test.py @@ -46,10 +46,10 @@ from tm.obsw_tm_service_1 import pusPacketInfoService1T from tm.obsw_pus_tm_base import TmDictionaryKeys from tm.obsw_pus_tm_factory import PusTmInfoQueueT, PusTmInfoT from sendreceive.obsw_multiple_commands_sender_receiver import MultipleCommandSenderReceiver - +from utility.obsw_logger import get_logger TmInfoQueueService1T = Deque[pusPacketInfoService1T] - +LOGGER = get_logger() class TestService(unittest.TestCase): """ @@ -116,11 +116,19 @@ class TestService(unittest.TestCase): com_interface=self.communication_interface, tmtc_printer=self.tmtc_printer, tm_listener=self.tm_listener, tc_queue=self.test_queue, wait_intervals=self.wait_intervals, wait_time=self.wait_time, print_tm=g.G_PRINT_RAW_TM) - (tc_info_queue, tm_tuple_queue) = module_tester.send_tc_queue_and_return_info() + tc_info_queue = deque() + tm_packet_queue = deque() + try: + (tc_info_queue, tm_packet_queue) = module_tester.send_tc_queue_and_return_info() + except (IOError, KeyboardInterrupt): + LOGGER.info("Closing TMTC Handler") tm_info_queue = deque() - while tm_tuple_queue.__len__() != 0: - (tm_info, tm_packet) = tm_tuple_queue.pop() - tm_info_queue.append(tm_info) + while tm_packet_queue.__len__() != 0: + tm_packet = tm_packet_queue.pop() + # LOGGER.debug(tm_packet) + tm_info_queue.appendleft(tm_packet.pack_tm_information()) + g.G_PP.pprint(tm_info_queue) + g.G_PP.pprint(tc_info_queue) assertion_dict = self._analyse_tm_tc_info(tm_info_queue, tc_info_queue) return assertion_dict @@ -173,10 +181,14 @@ class TestService(unittest.TestCase): this function looks whether the tc verification SSC matched a source sequence count of the sent TM """ + LOGGER.debug(current_tm_info[TmDictionaryKeys.TC_SSC]) + LOGGER.debug(self.tc_ssc_array) current_subservice = current_tm_info[TmDictionaryKeys.SUBSERVICE] for possible_index, search_index in enumerate(self.tc_ssc_array): if search_index == current_tm_info[TmDictionaryKeys.TC_SSC]: + LOGGER.debug("ssc fitting") if current_subservice == 1: + LOGGER.debug("subservice1detected") self.tc_verified_start = self.tc_verified_start + 1 elif current_subservice == 5: self.tc_verified_step = self.tc_verified_step + 1 @@ -207,6 +219,7 @@ class TestService(unittest.TestCase): current_tm_info = tm_info_queue.pop() # Tc verification scanning is generic and has been moved to the superclass if current_tm_info[TmDictionaryKeys.SERVICE] == 1: + LOGGER.debug("detected") self.scan_for_respective_tc(current_tm_info) # Here, the desired event Id or RID can be specified if current_tm_info[TmDictionaryKeys.SERVICE] == 5: