diff --git a/.idea/runConfigurations/OBSW_UdpClient_Software_Serial.xml b/.idea/runConfigurations/OBSW_UdpClient_Software_Serial.xml index d5df69de126d841fb996447f952f2593ee8c8911..a1a1c3eb4071aa6ed2c95151b01dba14ae6c529a 100644 --- a/.idea/runConfigurations/OBSW_UdpClient_Software_Serial.xml +++ b/.idea/runConfigurations/OBSW_UdpClient_Software_Serial.xml @@ -13,7 +13,7 @@ <option name="ADD_SOURCE_ROOTS" value="true" /> <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> <option name="SCRIPT_NAME" value="$PROJECT_DIR$/OBSW_TmTcClient.py" /> - <option name="PARAMETERS" value="-m 4 -p -c 1 --hk" /> + <option name="PARAMETERS" value="-m 4 -p -c 1 --hk -t 5" /> <option name="SHOW_COMMAND_LINE" value="false" /> <option name="EMULATE_TERMINAL" value="false" /> <option name="MODULE_MODE" value="false" /> diff --git a/OBSW_TmTcClient.py b/OBSW_TmTcClient.py index 0f3e3f411e95af730fdc625b36bb2b9bcb2c800c..ac2e0d63658acab7e54728b9959d17eba4bb9b7d 100644 --- a/OBSW_TmTcClient.py +++ b/OBSW_TmTcClient.py @@ -111,14 +111,15 @@ def main(): SenderAndReceiver = SequentialCommandSenderReceiver( comInterface=communicationInterface, tmtcPrinter=tmtcPrinter, tmTimeout=g.tmTimeout, tcQueue=serviceTestSelect(g.service, serviceQueue), tcTimeoutFactor=g.tcSendTimeoutFactor, - doPrintToFile=g.printToFile) + doPrintToFile=g.printToFile, tmListener=tmListener) SenderAndReceiver.sendQueueTcAndReceiveTmSequentially() elif g.modeId == "SoftwareTestMode": allTcQueue = createTotalTcQueue() SenderAndReceiver = SequentialCommandSenderReceiver( comInterface=communicationInterface, tmtcPrinter=tmtcPrinter, tmTimeout=g.tmTimeout, - tcQueue=allTcQueue, tcTimeoutFactor=g.tcSendTimeoutFactor, doPrintToFile=g.printToFile) + tcQueue=allTcQueue, tcTimeoutFactor=g.tcSendTimeoutFactor, doPrintToFile=g.printToFile, + tmListener=tmListener) SenderAndReceiver.sendQueueTcAndReceiveTmSequentially() elif g.modeId == "OBSWUnitTest": @@ -131,6 +132,10 @@ def main(): else: print("Unknown Mode, Configuration error !") exit() + # At some later point, the program will run permanently and be able to take commands. For now + # we put a permanent loop here so the program doesnt exit automatically (TM Listener is daemonic) + while True: + pass # Prepare command for single command testing diff --git a/sendreceive/OBSW_SequentialSenderReceiver.py b/sendreceive/OBSW_SequentialSenderReceiver.py index 4215be1f91c9686212d95833b96101cc7bf179ab..2804bd85df873a436c8c130b14f80a6dad15c729 100644 --- a/sendreceive/OBSW_SequentialSenderReceiver.py +++ b/sendreceive/OBSW_SequentialSenderReceiver.py @@ -25,14 +25,12 @@ class SequentialCommandSenderReceiver(CommandSenderReceiver): def __init__(self, comInterface: ComIF_T, tmtcPrinter: TmTcPrinterT, tmListener: TmListenerT, tmTimeout: int, tcQueue, tcTimeoutFactor: int, doPrintToFile: bool): """ - - :param comInterface: - :param tmtcPrinter: - :param tmListener: - :param tmTimeout: - :param tcQueue: - :param tcTimeoutFactor: - :param doPrintToFile: + :param comInterface: CommunicationInterface object, passed on to CommandSenderReceiver + :param tmListener: TmListener object which runs in the background and receives all Telemetry + :param tmtcPrinter: TmTcPrinter object, passed on to CommandSenderReceiver + :param tmTimeout: TM Timeout. After each sent telecommand, listen for TMs for this time period + :param tcTimeoutFactor: If TM is not received, resend TC after tmTimeout * tcSendTimeoutFactor + :param doPrintToFile: Specify whether output is also printed to a file """ super().__init__( comInterface=comInterface, tmtcPrinter=tmtcPrinter, tmListener=tmListener, tmTimeout=tmTimeout, @@ -43,15 +41,10 @@ class SequentialCommandSenderReceiver(CommandSenderReceiver): self.start_time = 0 self.elapsed_time = 0 self.abortFlag = False - self.seqSenderActive = threading.Event() - self.seqSenderActive.set() def sendQueueTcAndReceiveTmSequentially(self): self.tmListener.modeId = g.modeList[3] self.tmListener.modeChangeEvent.set() - # receiverThread = threading.Thread(target=self.checkForMultipleReplies) - # receiverThread.start() - # time.sleep(0.5) self.sendAndReceiveFirstPacket() # this flag is set in the separate thread ! try: @@ -66,20 +59,19 @@ class SequentialCommandSenderReceiver(CommandSenderReceiver): while not self.tcQueue.empty(): self.performNextTcSend() if self.tcQueue.empty(): - print("TC Sender: TC queue empty") self.start_time = time.time() self.checkForTimeout() + print("Sequential SenderReceiver: All replies received!") + self.tmListener.modeOpFinished.set() if self.doPrintToFile: - print("Exporting output to log file.") + print("Sequential SenderReceiver: Exporting output to log file.") self.tmtcPrinter.printToFile() - # self.comInterface.performListenerMode() - - # def handleInterrupt(self, receiverThread): - # print("Keyboard Interrupt detected") - # self.run_event.clear() - # receiverThread.join() + print("Listening for packages ...") def performNextTcSend(self): + if self.tmListener.replyEvent.is_set(): + self.replyReceived = True + self.tmListener.replyEvent.clear() # this flag is set in the separate receiver thread too if self.replyReceived: self.sendNextTelecommand() @@ -103,35 +95,7 @@ class SequentialCommandSenderReceiver(CommandSenderReceiver): elif self.tcQueue.empty(): # Special case: Last queue entry is not a Telecommand self.allRepliesReceived = True - print("Receiver: All replies received") else: - self.replyReceived = True + # If the queue entry was not a telecommand, send next telecommand self.performNextTcSend() - # this function runs is a separate thread and checks for replies. If the first reply has not been received, - # it attempts to send the telecommand again. - # if the tc queue is empty and the last telemetry sequence has been received, - # a flag is set to transition into listener mode - def checkForMultipleReplies(self): - while not self.allRepliesReceived and self.seqSenderActive.is_set(): - # listen for duration timeoutInSeconds for replies - self.handleReplyListening() - - def handleReplyListening(self): - if self.firstReplyReceived: - if self.tmListener.replyEvent.is_set(): - self.replyReceived = True - self.tmListener.replyEvent.clear() - if self.tcQueue.empty(): - print("All replies recevied !") - self.tmListener.modeOpFinished.set() - self.allRepliesReceived = True - else: - self.handleFirstReplyListening() - - def handleFirstReplyListening(self): - while not self.firstReplyReceived and self.seqSenderActive.is_set(): - # this function sends the telecommand again if no reply is received - self.checkForFirstReply() - if self.replyReceived: - self.firstReplyReceived = True diff --git a/sendreceive/OBSW_SingleCommandSenderReceiver.py b/sendreceive/OBSW_SingleCommandSenderReceiver.py index 137ed265dd76b3989e93b3703c5bc35299118f9f..36383c8202fc07edceb96b85bf554c69cbd1d746 100644 --- a/sendreceive/OBSW_SingleCommandSenderReceiver.py +++ b/sendreceive/OBSW_SingleCommandSenderReceiver.py @@ -46,6 +46,7 @@ class SingleCommandSenderReceiver(CommandSenderReceiver): # wait until reply is received super().checkForFirstReply() if self.replyReceived: + print("Single Command SenderReceiver: Reply received") self.tmListener.modeOpFinished.set() print("Listening for packages ...") diff --git a/sendreceive/OBSW_TmListener.py b/sendreceive/OBSW_TmListener.py index 865dd656683c7b0036b3bf46d6167bdb2bd9194d..34ee2339b56f6c64e310d58b1f6747cb16412f0f 100644 --- a/sendreceive/OBSW_TmListener.py +++ b/sendreceive/OBSW_TmListener.py @@ -34,6 +34,8 @@ class TmListener: self.listenerActive = threading.Event() # TM Listener operations can be suspended by setting this flag self.listenerActive.set() # I don't think a listener is useful without the main program, so we might just declare it daemonic. + # UPDATE: Right now, the main program is not in a permanent loop and setting the thread daemonic will + # cancel the program self.listenerThread = threading.Thread(target=self.performOperation, daemon=True) # This Event is set by sender objects to perform mode operations self.modeChangeEvent = threading.Event() @@ -60,9 +62,9 @@ class TmListener: # TODO: We should put this in a timeout.. Each mode operation up until now only takes # a maximum specified time (software test 5 minutes maybe?). Otherwise, this is a permanent loop self.modeChangeEvent.clear() - self.modeId = g.modeList[1] # After Mode Operation, mode will be listener mode. while not self.modeOpFinished.is_set(): self.performModeOperation() + self.modeId = g.modeList[1] def performModeOperation(self): """ @@ -79,12 +81,10 @@ class TmListener: if self.checkForOneTelemetrySequence(): # Set reply event, will be cleared by checkForFirstReply() self.replyEvent.set() - print("All replies received!") - self.replyEvent.set() # Sequential Command Mode elif self.modeId == g.modeList[3]: if self.checkForOneTelemetrySequence(): - print("Reply sequence received!") + print("TM Listener: Reply sequence received!") self.replyEvent.set() def checkForOneTelemetrySequence(self) -> bool: