diff --git a/.idea/runConfigurations/OBSW_TmTcClient_Service_2_Serial.xml b/.idea/runConfigurations/OBSW_TmTcClient_Service_2_Serial.xml index b6ff584ddc02495e04a7867ec82171d934a4faea..2ef32e159ff1dff6dd45d83b9fbc5aac6244b11d 100644 --- a/.idea/runConfigurations/OBSW_TmTcClient_Service_2_Serial.xml +++ b/.idea/runConfigurations/OBSW_TmTcClient_Service_2_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_tmtc_client.py" /> - <option name="PARAMETERS" value="-m 3 -s 2 -c 1 --COM /dev/ttyUSB1" /> + <option name="PARAMETERS" value="-m 3 -s 2 -c 1" /> <option name="SHOW_COMMAND_LINE" value="false" /> <option name="EMULATE_TERMINAL" value="false" /> <option name="MODULE_MODE" value="false" /> diff --git a/.idea/runConfigurations/OBSW_TmTcClient_Service_3_Serial_.xml b/.idea/runConfigurations/OBSW_TmTcClient_Service_3_Serial_.xml index 889e53d68d424b2178c7af179021940fe142decf..fdc43dd749450981f15ad87f0937250ac24dcf55 100644 --- a/.idea/runConfigurations/OBSW_TmTcClient_Service_3_Serial_.xml +++ b/.idea/runConfigurations/OBSW_TmTcClient_Service_3_Serial_.xml @@ -12,7 +12,7 @@ <option name="ADD_CONTENT_ROOTS" value="true" /> <option name="ADD_SOURCE_ROOTS" value="true" /> <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> - <option name="SCRIPT_NAME" value="C:\Users\Robin\NoSyncDokumente\sourceobsw\tmtc\obsw_tmtc_client.py" /> + <option name="SCRIPT_NAME" value="$PROJECT_DIR$/obsw_tmtc_client.py" /> <option name="PARAMETERS" value="-m 3 -s 3 -p -c 1 -t 4 --hk" /> <option name="SHOW_COMMAND_LINE" value="false" /> <option name="EMULATE_TERMINAL" value="false" /> diff --git a/.idea/runConfigurations/OBSW_TmTcClient__Service_200_Serial.xml b/.idea/runConfigurations/OBSW_TmTcClient__Service_200_Serial.xml new file mode 100644 index 0000000000000000000000000000000000000000..3ece0d3eaf7e29f8e12d3315e5112a8c94130d53 --- /dev/null +++ b/.idea/runConfigurations/OBSW_TmTcClient__Service_200_Serial.xml @@ -0,0 +1,24 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="OBSW_TmTcClient Service 200 Serial" type="PythonConfigurationType" factoryName="Python" folderName="Serial Communication"> + <module name="tmtc" /> + <option name="INTERPRETER_OPTIONS" value="" /> + <option name="PARENT_ENVS" value="true" /> + <envs> + <env name="PYTHONUNBUFFERED" value="1" /> + </envs> + <option name="SDK_HOME" value="" /> + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> + <option name="IS_MODULE_SDK" value="true" /> + <option name="ADD_CONTENT_ROOTS" value="true" /> + <option name="ADD_SOURCE_ROOTS" value="true" /> + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> + <option name="SCRIPT_NAME" value="$PROJECT_DIR$/obsw_tmtc_client.py" /> + <option name="PARAMETERS" value="-m 3 -s 200 -c 1 --hk -t 5" /> + <option name="SHOW_COMMAND_LINE" value="false" /> + <option name="EMULATE_TERMINAL" value="false" /> + <option name="MODULE_MODE" value="false" /> + <option name="REDIRECT_INPUT" value="false" /> + <option name="INPUT_FILE" value="" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/OBSW_UdpClient_Listener_Serial.xml b/.idea/runConfigurations/OBSW_UdpClient_Listener_Serial.xml new file mode 100644 index 0000000000000000000000000000000000000000..1d9915ed48d8dc6e38281082a1099384cbf24c3f --- /dev/null +++ b/.idea/runConfigurations/OBSW_UdpClient_Listener_Serial.xml @@ -0,0 +1,24 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="OBSW_UdpClient Listener Serial" type="PythonConfigurationType" factoryName="Python" folderName="Serial Communication"> + <module name="tmtc" /> + <option name="INTERPRETER_OPTIONS" value="" /> + <option name="PARENT_ENVS" value="true" /> + <envs> + <env name="PYTHONUNBUFFERED" value="1" /> + </envs> + <option name="SDK_HOME" value="" /> + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> + <option name="IS_MODULE_SDK" value="true" /> + <option name="ADD_CONTENT_ROOTS" value="true" /> + <option name="ADD_SOURCE_ROOTS" value="true" /> + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> + <option name="SCRIPT_NAME" value="$PROJECT_DIR$/obsw_tmtc_client.py" /> + <option name="PARAMETERS" value="-m 1 --hk -c 1" /> + <option name="SHOW_COMMAND_LINE" value="false" /> + <option name="EMULATE_TERMINAL" value="false" /> + <option name="MODULE_MODE" value="false" /> + <option name="REDIRECT_INPUT" value="false" /> + <option name="INPUT_FILE" value="" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/OBSW_UdpClient_Service_17_Serial.xml b/.idea/runConfigurations/OBSW_UdpClient_Service_17_Serial.xml new file mode 100644 index 0000000000000000000000000000000000000000..f5a39bfb451e02dddc3f727b75d572522260b1ab --- /dev/null +++ b/.idea/runConfigurations/OBSW_UdpClient_Service_17_Serial.xml @@ -0,0 +1,24 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="OBSW_UdpClient Service 17 Serial" type="PythonConfigurationType" factoryName="Python" folderName="Serial Communication"> + <module name="tmtc" /> + <option name="INTERPRETER_OPTIONS" value="" /> + <option name="PARENT_ENVS" value="true" /> + <envs> + <env name="PYTHONUNBUFFERED" value="1" /> + </envs> + <option name="SDK_HOME" value="" /> + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> + <option name="IS_MODULE_SDK" value="true" /> + <option name="ADD_CONTENT_ROOTS" value="true" /> + <option name="ADD_SOURCE_ROOTS" value="true" /> + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> + <option name="SCRIPT_NAME" value="$PROJECT_DIR$/obsw_tmtc_client.py" /> + <option name="PARAMETERS" value="-m 3 -s 17 -c 1 -t 5" /> + <option name="SHOW_COMMAND_LINE" value="false" /> + <option name="EMULATE_TERMINAL" value="true" /> + <option name="MODULE_MODE" value="false" /> + <option name="REDIRECT_INPUT" value="false" /> + <option name="INPUT_FILE" value="" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/.idea/runConfigurations/OBSW_UdpClient_Single_Command_Serial_.xml b/.idea/runConfigurations/OBSW_UdpClient_Single_Command_Serial_.xml new file mode 100644 index 0000000000000000000000000000000000000000..63420a0c91db797a78269aaa2efd27a1065c6c7b --- /dev/null +++ b/.idea/runConfigurations/OBSW_UdpClient_Single_Command_Serial_.xml @@ -0,0 +1,24 @@ +<component name="ProjectRunConfigurationManager"> + <configuration default="false" name="OBSW_UdpClient Single Command Serial " type="PythonConfigurationType" factoryName="Python" folderName="Serial Communication"> + <module name="tmtc" /> + <option name="INTERPRETER_OPTIONS" value="" /> + <option name="PARENT_ENVS" value="true" /> + <envs> + <env name="PYTHONUNBUFFERED" value="1" /> + </envs> + <option name="SDK_HOME" value="" /> + <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> + <option name="IS_MODULE_SDK" value="true" /> + <option name="ADD_CONTENT_ROOTS" value="true" /> + <option name="ADD_SOURCE_ROOTS" value="true" /> + <EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" /> + <option name="SCRIPT_NAME" value="$PROJECT_DIR$/obsw_tmtc_client.py" /> + <option name="PARAMETERS" value="-m 2 -c 1 -t 5" /> + <option name="SHOW_COMMAND_LINE" value="false" /> + <option name="EMULATE_TERMINAL" value="false" /> + <option name="MODULE_MODE" value="false" /> + <option name="REDIRECT_INPUT" value="false" /> + <option name="INPUT_FILE" value="" /> + <method v="2" /> + </configuration> +</component> \ No newline at end of file diff --git a/README.md b/README.md index 01696616a0bfd1aed2884f8ad280a2d2efa3a71c..d6cc47cce2eed46101a1c9209306f820c6cbca67 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ TMTC Client ## Prerequisites Runs with Python 3.8. Don't use Python 2.x! -Manual installation of crcmod might be needed +Manual installation of crcmod and pyserial might be needed 1. Install pip if it is not installed yet - 2. Install crcmod and all other reqiored packages: + 2. Install crcmod and all other required packages: Command: python<version> -m pip<version> install crcmod or use IDE (interpreter settings -> pip in PyCharm) @@ -30,9 +30,9 @@ Example to run Unit Test: obsw_tmtc_client.py -m 5 ``` Example to test service 3 with serial communication, printing all housekeeping packets, -and exporting to a log file. COM port needs to be typed in manually (or set with --COM \<COM PORT>): +COM port needs to be typed in manually (or set with --COM \<COM PORT>): ```shell script -obsw_tmtc_client.py -m 3 -s 3 -p --hk -c +obsw_tmtc_client.py -m 3 -s 3 --hk -c ``` ## Modes @@ -61,16 +61,26 @@ Please ensure that python.exe UDP packets are not blocked in advanced firewall s and create a rule to allow packets from port 2008. ## Serial Communication -Implemented. +Serial communication was implemented and is tested for Windwos 10. +It requires the PySerial package installed. -## Unit Test +## Module Test +Includes a moduel tester which sends TCs in a queue and automatically +analyzes the replies. This is the best way to test the functionality of the +software right now as a software internal TC injector has not been implemented +yet for the FSFW. Some more information will follow on how to write Unit Tests. ## Developers Information -Code Style: [PEP8](https://www.python.org/dev/peps/pep-0008/) +Code Style: [PEP8](https://www.python.org/dev/peps/pep-0008/). + Can be enforced/checked by using Pylint as an external program in PyCharm. Install it with pip and then install and set-up the Pylint plugin in PyCharm. +There are a lot of features which would be nice, for example a GUI. +The architecture of the program should allow extension like that without +too many issues, as the sending and telemetry listening are decoupled. + ## Import run configurations in PyCharm The PyCharm IDE can be used to comfortably manage a set of run configuations (for example tests for different services). These configurations were shared through the version control system Git diff --git a/comIF/obsw_com_interface.py b/comIF/obsw_com_interface.py index 0b271f219ca24a6393900cf574bd4bfa7d7b8886..6f3f80debfbdc73447743f535f5d546cc5d49e06 100644 --- a/comIF/obsw_com_interface.py +++ b/comIF/obsw_com_interface.py @@ -38,8 +38,8 @@ class CommunicationInterface: def send_telecommand(self, tc_packet: bytearray, tc_packet_info: PusTcInfoT = None) -> None: """ Send telecommands - :param tc_packet: TC packet to send - :param tc_packet_info: TC packet information + :param tc_packet: TC wiretapping_packet to send + :param tc_packet_info: TC wiretapping_packet information :return: None for now """ @@ -59,8 +59,8 @@ class CommunicationInterface: """ Poll the interface and return a list of received packets :param parameters: - :return: Tuple: boolean which specifies wheather a packet was received, - and the packet list containing + :return: Tuple: boolean which specifies wheather a wiretapping_packet was received, + and the wiretapping_packet list containing Tm packets """ @@ -75,7 +75,7 @@ class CommunicationInterface: def receive_telemetry_and_store_info(self, tm_info_queue: PusTmInfoQueueT) -> \ Union[None, PusTmInfoQueueT]: """ - Receive telemetry and store packet information in dict format into a queue. + Receive telemetry and store wiretapping_packet information in dict format into a queue. If no _tm_data is available, don't do anything. :param tm_info_queue: :return: @@ -97,7 +97,7 @@ class CommunicationInterface: Union[None, PusTmTupleQueueT]: """ Poll telemetry and store a tuple consisting of TM information and the - TM packet into the queue. If no _tm_data is available, don't do anything. + TM wiretapping_packet into the queue. If no _tm_data is available, don't do anything. :param tm_tuple_queue: :return: """ diff --git a/comIF/obsw_serial_com_if.py b/comIF/obsw_serial_com_if.py index 7a9055950619156567ddbc6f37ff796db2172e2b..cd25af9e5a86c3779747e628a3a7ca854165fa1c 100644 --- a/comIF/obsw_serial_com_if.py +++ b/comIF/obsw_serial_com_if.py @@ -87,7 +87,7 @@ class SerialComIF(CommunicationInterface): read_size = len(self.data) self.number_of_packets = 1 if read_size < packet_size: - print("Serial Com IF: Size missmatch when polling PUS packet. Packet Size: " + + print("Serial Com IF: Size missmatch when polling PUS wiretapping_packet. Packet Size: " + str(packet_size) + ". Read Size: " + str(read_size) + ". Check timeout too") if read_size > packet_size: self.__handle_multiple_packets(packet_size, read_size, pus_data_list) @@ -109,8 +109,8 @@ class SerialComIF(CommunicationInterface): end_index = end_index + 5 next_packet_size = (self.data[end_index - 1] << 8 | self.data[end_index]) + 7 if next_packet_size > SERIAL_PACKET_MAX_SIZE: - print("PUS Polling: Very Large packet detected, " - "large packet reading not implemented yet !") + print("PUS Polling: Very Large wiretapping_packet detected, " + "large wiretapping_packet reading not implemented yet !") print("Detected Size: " + str(next_packet_size)) return SERIAL_PACKET_MAX_SIZE end_index = start_index + next_packet_size diff --git a/sendreceive/obsw_command_sender_receiver.py b/sendreceive/obsw_command_sender_receiver.py index 6de785feb7deb6599bc3fbba88ab18ff2dfc39bf..6456c171d27f06871c450a9ef1654db8ebb915dd 100644 --- a/sendreceive/obsw_command_sender_receiver.py +++ b/sendreceive/obsw_command_sender_receiver.py @@ -57,7 +57,7 @@ class CommandSenderReceiver: self._elapsed_time = 0 self._timeout_counter = 0 - # needed to store last actual tc packet from queue + # needed to store last actual tc wiretapping_packet from queue self._last_tc = bytearray() self._last_tc_info = dict() diff --git a/sendreceive/obsw_tm_listener.py b/sendreceive/obsw_tm_listener.py index 64a6e699ea0578a725c991fc12e5aa6419fbd629..cd935aabb750fef37d79c6e3dbc6cc8a25f9222c 100644 --- a/sendreceive/obsw_tm_listener.py +++ b/sendreceive/obsw_tm_listener.py @@ -121,7 +121,7 @@ class TmListener: if tmReady: self.comInterface.receive_telemetry() elapsed_time = time.time() - start_time - # the timeout value can be set by special TC queue entries if packet handling + # the timeout value can be set by special TC queue entries if wiretapping_packet handling # takes longer, but it is reset here to the global value if self.tmTimeout is not g.G_TM_TIMEOUT: self.tmTimeout = g.G_TM_TIMEOUT diff --git a/tc/obsw_pus_tc_base.py b/tc/obsw_pus_tc_base.py index 6b4858558bc94e83c485bf7a8f1b8d4a11a116f9..473f4c2345dad769a94650c5f1af7cf4629d4fd6 100644 --- a/tc/obsw_pus_tc_base.py +++ b/tc/obsw_pus_tc_base.py @@ -94,7 +94,7 @@ class PusTelecommand: # Takes pusPackets, removes current Packet Error Control, -# calculates new CRC (16 bits at packet end) and +# calculates new CRC (16 bits at wiretapping_packet end) and # adds it as correct Packet Error Control Code. Reference: ECSS-E70-41A p. 207-212 def generatePacketCRC(TCPacket: PusTcT) -> PusTcT: crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000) @@ -116,7 +116,7 @@ def generateCRC(data: bytearray) -> bytearray: # pylint: disable=line-too-long # Structure of a PUS TC Packet : -# A PUS packet consists of consecutive bits, the allocation and structure is standardised. +# 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 diff --git a/tm/obsw_pus_tm_base.py b/tm/obsw_pus_tm_base.py index 012cc49fc744d84ee009668e98c3b52239396614..60a47357465d28070e0ab5827674816a460b4400 100644 --- a/tm/obsw_pus_tm_base.py +++ b/tm/obsw_pus_tm_base.py @@ -1,5 +1,5 @@ """ -@brief: Generic PUS packet class to deserialize raw PUS telemetry. +@brief: Generic PUS wiretapping_packet class to deserialize raw PUS telemetry. @date: 09.04.2020 @author: R.Mueller, S. Gaisser """ @@ -21,9 +21,9 @@ PusTmTupleQueueT = Deque[PusTmTupleT] class PusTelemetry: """ - Generic PUS telemetry class. 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. + Generic PUS telemetry class. It is instantiated by passing the raw pus telemetry wiretapping_packet + (bytearray) to the constructor. It automatically deserializes the wiretapping_packet, exposing + various wiretapping_packet fields via getter functions. """ def __init__(self, byte_array: bytes): self._packet_raw: Final = byte_array @@ -109,14 +109,14 @@ class PusTelemetry: def get_raw_packet(self) -> bytearray: """ - Get the whole TM packet as a bytearray (raw) - :return: TM packet + Get the whole TM wiretapping_packet as a bytearray (raw) + :return: TM wiretapping_packet """ return self._packet_raw def get_packet_size(self) -> int: """ - :return: Size of the TM packet + :return: Size of the TM wiretapping_packet """ # PusHeader Size + _tm_data size size = PusPacketHeader.PUS_HEADER_SIZE + self._pus_header.length + 1 @@ -137,7 +137,8 @@ class PusTelemetry: str_to_print = "[" for byte in self._tm_data: str_to_print += str(hex(byte)) + " , " - 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 @@ -152,7 +153,7 @@ class PusTelemetry: # pylint: disable=too-many-instance-attributes class PusPacketHeader: """ - This class unnpacks the PUS packet header (see PUS structure below or PUS documentation) + This class unnpacks the PUS wiretapping_packet header (see PUS structure below or PUS documentation) """ PUS_HEADER_SIZE = 6 @@ -178,7 +179,7 @@ class PusPacketHeader: self.valid = False crc_func = crcmod.mkCrcFun(0x11021, rev=False, initCrc=0xFFFF, xorOut=0x0000) if len(data_to_check) < ((self.length + 1) + PusPacketHeader.PUS_HEADER_SIZE): - print("Invalid packet length") + print("Invalid wiretapping_packet length") return data_to_check = data_to_check[0:(self.length + 1) + PusPacketHeader.PUS_HEADER_SIZE] crc = crc_func(data_to_check) @@ -236,7 +237,7 @@ class ObswPusPacketDataFieldHeader: class ObswTimestamp: """ - Unpacks the time datafield of the TM packet. + Unpacks the time datafield of the TM wiretapping_packet. """ def __init__(self, byteArray): # pField = byte_array[0] @@ -261,7 +262,7 @@ class ObswTimestamp: # pylint: disable=line-too-long # Structure of a PUS Packet : -# A PUS packet consists of consecutive bits, the allocation and structure is standardised. +# 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 diff --git a/tm/obsw_pus_tm_factory.py b/tm/obsw_pus_tm_factory.py index 125127e2633f13fa2bb73765913c2df00977cf7a..55bbc7c7b6b2e4ffa65ef3ae7893bb6466fa7b2f 100644 --- a/tm/obsw_pus_tm_factory.py +++ b/tm/obsw_pus_tm_factory.py @@ -15,9 +15,9 @@ import struct def PusTelemetryFactory(raw_packet: bytes): """ - Returns a PusTelemetry class instance by extracting the service directly from the raw packet. + Returns a PusTelemetry class instance by extracting the service directly from the raw wiretapping_packet. Sneaky solution allows this function to immediately return - the right telemetry packet + the right telemetry wiretapping_packet :param raw_packet: :return: """ diff --git a/utility/obsw_tmtc_printer.py b/utility/obsw_tmtc_printer.py index c28a4e227cedd920ba60ad4965deb674b76ac8cf..74aeef33632c198bb88e95ae4e31251221204c8e 100644 --- a/utility/obsw_tmtc_printer.py +++ b/utility/obsw_tmtc_printer.py @@ -157,16 +157,17 @@ class TmTcPrinter: print(self.print_buffer) self.add_print_buffer_to_file_buffer() - def __handle_wiretapping_packet(self, packet): + def __handle_wiretapping_packet(self, wiretapping_packet: PusTelemetry): """ - :param packet: + :param wiretapping_packet: :return: """ - if packet.get_service() == 2 and \ - (packet.get_subservice() == 131 or packet.get_subservice() == 130): + if wiretapping_packet.get_service() == 2 and (wiretapping_packet.get_subservice() == 131 or + wiretapping_packet.get_subservice() == 130): self.print_buffer = "Wiretapping Packet or Raw Reply from TM [" + \ - str(packet.get_service()) + "," + str(packet.get_subservice()) + "]:" - self.print_buffer = self.print_buffer + packet.return_data_string() + str(wiretapping_packet.get_service()) + "," + \ + str(wiretapping_packet.get_subservice()) + "]: " + self.print_buffer = self.print_buffer + wiretapping_packet.return_data_string() print(self.print_buffer) self.add_print_buffer_to_file_buffer() @@ -260,10 +261,10 @@ class TmTcPrinter: """ if self.print_tc: if len(tc_packet) == 0: - print("TMTC Printer: Empty packet was sent, configuration error") + print("TMTC Printer: Empty wiretapping_packet was sent, configuration error") sys.exit() if tc_packet_info is None: - print("TMTC Printer: No packet info supplied to print") + print("TMTC Printer: No wiretapping_packet info supplied to print") return if self.display_mode == "short": self.__handle_short_tc_print(tc_packet_info)