Skip to content
Snippets Groups Projects
Forked from an inaccessible project.
OBSW_CommandSenderReceiver.py 4.87 KiB
"""
Program: OBSW_UnitTest.py
Date: 01.11.2019
Description: All functions related to TmTc Sending and Receiving, used by UDP client

Manual:
Set up the UDP client as specified in the header comment and use the unit testing mode

A separate thread is used to listen for replies and send a new telecommand
if the first reply has not been received.

@author: R. Mueller
"""
import time
from comIF.OBSW_ComInterface import CommunicationInterface, ComIF_T
from utility.OBSW_TmTcPrinter import TmTcPrinterT, TmTcPrinter
from sendreceive.OBSW_TmListener import TmListenerT, TmListener


class CommandSenderReceiver:
    """
    This is the generic CommandSenderReceiver object. All TMTC objects inherit this object,
    for example specific implementations (e.g. SingleCommandSenderReceiver)
    """
    def __init__(self, comInterface: ComIF_T, tmtcPrinter: TmTcPrinterT, tmListener: TmListenerT, tmTimeout: float,
                 tcSendTimeoutFactor: float, doPrintToFile: bool):
        """
        :param comInterface: CommunicationInterface object. Instantiate the desired one and pass it here
        :param tmtcPrinter: TmTcPrinter object. Instantiate it and pass it here.
        :param tmTimeout: TM Timeout. After each sent telecommand, listen for TMs for this time period
        :param tcSendTimeoutFactor: If TM is not received, resend TC after tmTimeout * tcSendTimeoutFactor
        :param doPrintToFile: Specify whether output is also printed to a file
        """
        self.tmTimeout = tmTimeout

        if isinstance(comInterface, CommunicationInterface):
            self._comInterface = comInterface
        else:
            raise TypeError("Invalid communication interface type!")

        if isinstance(tmtcPrinter, TmTcPrinter):
            self._tmtcPrinter = tmtcPrinter
        else:
            raise TypeError("Invalid TMTC Printer type!")

        if isinstance(tmListener, TmListener):
            self._tmListener = tmListener
        else:
            raise TypeError("Invalid TM Listener type!")

        self.replyReceived = False
        self.tmReady = False
        self.pusPacketInfo = []
        self.pusPacket = []

        self.start_time = 0
        self.elapsed_time = 0
        self.timeoutCounter = 0
        self.tcSendTimeoutFactor = tcSendTimeoutFactor
        self.doPrintToFile = doPrintToFile
        self.queueEntryIsTelecommand = True

        # needed to store last actual tc packet from queue
        self.lastTc = bytearray()
        self.lastTcInfo = dict()
        # ignore periodic packets for timeout when checking a sequence
        self.isPacketToIgnore = False

    def checkForFirstReply(self) -> None:
        """
        Checks for replies. If no reply is received, send telecommand again in checkForTimeout()
        :return: None
        """
        if self._tmListener.replyEvent.is_set():
            self.replyReceived = True
            self._tmListener.replyEvent.clear()
        else:
            if len(self.pusPacket) == 0:
                print("Command Sender Receiver: No command has been sent yet")
            else:
                self.checkForTimeout()

    # Check for special queue entries.
    def checkQueueEntry(self, tcQueueEntry):
        (self.pusPacketInfo, self.pusPacket) = tcQueueEntry
        self.queueEntryIsTelecommand = False
        if self.pusPacketInfo == "wait":
            waitTime = self.pusPacket
            self.tmTimeout = self.tmTimeout + waitTime
            time.sleep(waitTime)
        elif self.pusPacketInfo == "print":
            printString = self.pusPacket
            self._tmtcPrinter.printString(printString)
        elif self.pusPacketInfo == "export":
            exportName = self.pusPacket
            if self.doPrintToFile:
                self._tmtcPrinter.printToFile(exportName, True)
        elif self.pusPacketInfo == "timeout":
            self.tmTimeout = self.pusPacket
        else:
            self.queueEntryIsTelecommand = True
            self.lastTc, self.lastTcInfo = (self.pusPacket, self.pusPacketInfo)

    def checkForTimeout(self):
        """
        Checks whether a timeout after sending a telecommand has occured and sends telecommand again.
        If resending reached certain counter, exit the program.
        :return:
        """
        if self.timeoutCounter == 5:
            print("Command Sender Receiver: No response from command !")
            exit()
        if self.start_time != 0:
            self.elapsed_time = time.time() - self.start_time
        if self.elapsed_time > self.tmTimeout * self.tcSendTimeoutFactor:
            print("Command Sender Receiver: Timeout, sending TC again !")
            self._comInterface.sendTelecommand(self.lastTc, self.lastTcInfo)
            self.timeoutCounter = self.timeoutCounter + 1
            self.start_time = time.time()
        time.sleep(0.5)