diff --git a/.gitignore b/.gitignore index 001c426..9c79f62 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,3 @@ *.pyc cmdUtil .DS_Store -Subsystems/cmdGui/CHeaderParser.py -Subsystems/cmdGui/CHeaderParser.py \ No newline at end of file diff --git a/GroundSystem.py b/GroundSystem.py index 29fe5cd..3688960 100644 --- a/GroundSystem.py +++ b/GroundSystem.py @@ -38,7 +38,6 @@ # CFS Ground System: Setup and manage the main window # class GroundSystem(QMainWindow, Ui_MainWindow): - # # Init the class # @@ -76,7 +75,6 @@ def getSelectedSpacecraftName(self): # def DisplayErrorMessage(self, message): print(message) - # alert = QMessageBox() self.alert.setText(message) self.alert.setIcon(QMessageBox.Warning) self.alert.exec_() @@ -104,14 +102,18 @@ def startCmdSystem(): ['python3', f'{ROOTDIR}/Subsystems/cmdGui/CommandSystem.py']) # Start FDL-FUL gui system - #def startFDLSystem(self): - # selectedSpacecraft = self.getSelectedSpacecraftName() - # if selectedSpacecraft == 'All': - # subscription = '' - # self.DisplayErrorMessage('Cannot open FDL manager.\nNo spacecraft selected.') - # else: - # subscription = '--sub=GroundSystem.' + selectedSpacecraft - # os.system('( cd Subsystems/fdlGui/ && python FdlSystem.py ' + subscription + ' ) & ') + def startFDLSystem(self): + selectedSpacecraft = self.getSelectedSpacecraftName() + if selectedSpacecraft == 'All': + subscription = '' + self.DisplayErrorMessage( + 'Cannot open FDL manager.\nNo spacecraft selected.') + else: + subscription = f'--sub=GroundSystem.{selectedSpacecraft}' + subprocess.Popen([ + 'python3', f'{ROOTDIR}/Subsystems/fdlGui/FdlSystem.py', + subscription + ]) # Update the combo box list in gui def updateIpList(self, ip, name): diff --git a/Guide-GroundSystem.md b/Guide-GroundSystem.md index fdc30f5..b8cf631 100644 --- a/Guide-GroundSystem.md +++ b/Guide-GroundSystem.md @@ -25,18 +25,17 @@ Future enhancements: ## Install and run Before launching the Ground System make sure that: - -- PyQt4 is installed, +- PyQt5 is installed, - PyZMQ is installed, - cmdUtil is compiled. Installing and running cFS Ground System on Ubuntu: -1. `sudo apt-get install python3-pyqt4` -2. `sudo apt-get install python3-zmq` -3. `sudo apt-get install libcanberra-gtk-module` -4. `cd Subsystems/cmdUtil/ && make` -5. `python3 GroundSystem.py` +1. ```sudo apt-get install python3-pyqt5``` +1. ```sudo apt-get install python3-zmq``` +1. ```sudo apt-get install libcanberra-gtk-module``` +1. ```cd Subsystems/cmdUtil/ && make``` +1. ```python3 GroundSystem.py``` The historically included instructions for running on macOS or CentOS are included at the bottom of this document for reference. Please note that instructions have not been maintained. Welcoming instruction contributions if any of these are your platform of choice. @@ -46,7 +45,8 @@ This section was made to help developers who are adding core Flight Software (cF The `CHeaderParser.py` program that should be found in: -````groundsystem/subsystems/cmdgui``` +```GroundSystem/Subsystems/cmdGui``` + Is an interactive, command-line based program to help walk developers through the process of adding custom cFS applications to the Ground System. Along with `CHeaderParser.py` is a configuration file that CHeaderParser uses to find the proper header files for your "new" cFS application. This file is named `CHeaderParser-hdr-paths.txt`, and should be placed in the same directory as `CHeaderParser.py`. Expected file structure: diff --git a/RoutingService.py b/RoutingService.py index 66b9e7d..47139ca 100644 --- a/RoutingService.py +++ b/RoutingService.py @@ -120,8 +120,6 @@ def forwardMessage(self, datagram, hostName): def getPktId(datagram): # Read the telemetry header streamId = unpack(">H", datagram[:2]) - # Uncomment the next line to debug - # print("Packet ID =", hex(streamId)) return hex(streamId[0]) # Close ZMQ vars diff --git a/Subsystems/cmdGui/CHeaderParser.py b/Subsystems/cmdGui/CHeaderParser.py index fcd48bd..52fd4dc 100644 --- a/Subsystems/cmdGui/CHeaderParser.py +++ b/Subsystems/cmdGui/CHeaderParser.py @@ -103,12 +103,6 @@ def getFileList(filename='CHeaderParser-hdr-paths.txt'): l = l.strip() if l and not l.startswith("#"): paths.append(l) - # Don't worry about comment lines - # if line.find('#') == -1: - # Don't worry about empty lines - # if line != '': - # Add line to list of paths - # paths.append(line) print(f"Using header files found in {filename}") # Send paths back to caller function return paths @@ -149,8 +143,6 @@ def getFileList(filename='CHeaderParser-hdr-paths.txt'): for single_line in single_hdr: master_hdr.append(single_line) - #print "Master Header Length: " + str(len(master_hdr)) - # Reads and saves command and parameter information # Look through each line of the header file for command definitions for single_line in master_hdr: @@ -180,9 +172,6 @@ def getFileList(filename='CHeaderParser-hdr-paths.txt'): # structure single_line = single_line[:single_line.rfind('//')] - #else: - # print "Did not find any comments in definition." - # Split single line into list for indexing definition = single_line.split() @@ -195,30 +184,15 @@ def getFileList(filename='CHeaderParser-hdr-paths.txt'): cmdDesc.append(definition[1]) cmdCodes.append(definition[2]) - #else: - # print "length not 3, see line below" - # print definition - - #print ("List of Command Descriptions Below:") - #print (cmdDesc) - #print ("--------------------------------------------------------------") - #print ("List of Command Codes Below:") - #print (cmdCodes) - #print ("--------------------------------------------------------------") - - print( - "We need to save the command into to a pickle file in 'CommandFile/'. " - ) - print( - "Please do not use any spaces/quotes in your filename. Ex: my_app_cmd_file" - ) + print(("We need to save the command into to a pickle file " + "in 'CommandFile/'.\nPlease do not use any spaces/quotes " + "in your filename. Ex: my_app_cmd_file")) cmd_file_name = input( "What would you like the command file to be saved as? ") # starting from last index (-1) going backward # (from example above) file_split[-2] = app_msg # therefore picklefile = CommandFiles/app_msg - #pickle_file = 'CommandFiles/'+file_split[-2] pickle_file = f'{ROOTDIR}/CommandFiles/{cmd_file_name}' # Open pickle file for storing command codes/descriptions @@ -456,14 +430,8 @@ def getFileList(filename='CHeaderParser-hdr-paths.txt'): print("Array size:", array_size) - # Set flag initially to false in order to get into while loop - # array_size_within_limit = False - - # Check conditions before loop to see if loop is even necessary - # array_size_within_limit = array_size.isdigit() and int( - # array_size) in range(129) - - # This while loop will make sure that the user input is both + # This while loop will make sure that + # the user input is both # - a valid integer # - between 0 and 128 (inclusively) while not array_size.isdigit() or int( diff --git a/Subsystems/cmdGui/CommandSystem.py b/Subsystems/cmdGui/CommandSystem.py index 2f3430b..710d780 100644 --- a/Subsystems/cmdGui/CommandSystem.py +++ b/Subsystems/cmdGui/CommandSystem.py @@ -76,7 +76,7 @@ def checkParams(idx): pickle_file = f'{ROOTDIR}/ParameterFiles/{quickParam[idx]}' try: with open(pickle_file, 'rb') as pickle_obj: - _, paramNames, _, _, _, _ = pickle.load(pickle_obj) + paramNames = pickle.load(pickle_obj)[1] return len(paramNames) > 0 except IOError: return False diff --git a/Subsystems/cmdGui/HTMLDocsParser.py b/Subsystems/cmdGui/HTMLDocsParser.py index 455f4ad..f932954 100644 --- a/Subsystems/cmdGui/HTMLDocsParser.py +++ b/Subsystems/cmdGui/HTMLDocsParser.py @@ -17,21 +17,14 @@ # See the License for the specific language governing permissions and # limitations under the License. # -import sys -import csv -import getopt -import subprocess -import shlex -import re + import glob import pickle - +import re from html.parser import HTMLParser -from struct import * class HTMLDocsParser(HTMLParser): - # # Initializes allData variable # @@ -42,15 +35,16 @@ def reset(self): # # Appends HTML file content to allData variable # - def handle_data(self, text): - if text.strip() != '': # excludes new lines - self.allData.append(text.strip()) + def handle_data(self, data): + if data.strip(): # excludes new lines + self.allData.append(data.strip()) # # Determines UNIX data type of parameter # - def findDataTypeNew(self, dataTypeOrig, paramLen): - if paramLen != '': # assumes all string types have length enclosed in brackets + @staticmethod + def findDataTypeNew(dataTypeOrig, paramLn): + if paramLn: # assumes all string types have length enclosed in brackets return '--string' if dataTypeOrig in ('uint8', 'boolean'): return '--byte' @@ -65,25 +59,25 @@ def findDataTypeNew(self, dataTypeOrig, paramLen): # # Determines character array size for string types # - def findStringLen(self, keyword): + @staticmethod + def findStringLen(kywd): hdr_files = glob.glob('../../../build/cpu1/inc/*.h') hdr_files += glob.glob('../../fsw/cfe-core/src/inc/cfe_*.h') hdr_files += glob.glob('../../fsw/mission_inc/cfe_mission_cfg.h') val = '' found = False - i = 0 + k = 0 - while not found and i < len(hdr_files): - with open(hdr_files[i]) as hdr_obj: + while not found and k < len(hdr_files): + with open(hdr_files[k]) as hdr_obj: file_lines = hdr_obj.readlines() - j = 0 - while found == False and j < len(file_lines): - if '#define ' + keyword in file_lines[j]: + l = 0 + while not found and l < len(file_lines): + if f'#define {kywd}' in file_lines[l]: found = True - val = file_lines[j].split()[2] - j += 1 - i += 1 - + val = file_lines[l].split()[2] + l += 1 + k += 1 return val @@ -104,7 +98,7 @@ def findStringLen(self, keyword): with open(html_file) as file_obj: # opens HTML file reader = file_obj.read() # reads HTML file parser.feed(reader) # feeds file contents to parser - data = parser.allData + allData = parser.allData dataTypesOrig = [] # uint8, uint16, uint32, char, boolean paramNames = [] # parameter name @@ -114,32 +108,35 @@ def findStringLen(self, keyword): stringLen = [] # evaluated parameter length try: - i = data.index("Data Fields") + 1 - j = data.index("Detailed Description") - while i < j: # iterates through lines between Data Fields and Detailed Description - + i = allData.index("Data Fields") + 1 + j = allData.index("Detailed Description") + # iterates through lines between Data Fields and Detailed Description + while i < j: # skips header parameters - if 'Header' in data[i + 1] or 'Hdr' in data[i + 1]: + if any([x in allData[i + 1] for x in ('Header', 'Hdr')]): + # if 'Header' in data[i + 1] or 'Hdr' in data[i + 1]: i += 1 - while 'uint' not in data[i] and 'char' not in data[ - i] and i < j: + while not any( + [x in allData[i] + for x in ('uint', 'char')]) and i < j: + # while 'uint' not in data[i] and 'char' not in data[ + # i] and i < j: i += 1 else: - dataTypesOrig.append(data[i]) # stores data type + dataTypesOrig.append(allData[i]) # stores data type i += 1 - paramNames.append(data[i]) # stores parameter name + paramNames.append(allData[i]) # stores parameter name i += 1 param_len = '' - if '[' in data[i]: - param_len = data[ + if '[' in allData[i]: + param_len = allData[ i] # stores string length if provided i += 1 paramLen.append(param_len) desc_string = '' - while 'uint' not in data[i] and 'char' not in data[ - i] and i < j: - desc_string = desc_string + ' ' + data[i] + while not any([x in allData[i] for x in ('uint', 'char')]) and i < j: + desc_string = f'{desc_string} {allData[i]}' i += 1 paramDesc.append(desc_string.lstrip() ) # stores parameter description @@ -152,15 +149,15 @@ def findStringLen(self, keyword): # finds size of character array if type --string keyword = '' if dataTypeNew == '--string': - keyword = re.sub('\[|\]|\(|\)', '', + keyword = re.sub(r'\[|\]|\(|\)', '', paramLen[-1]) # removes brackets - while keyword.isdigit() == False: + while not keyword.isdigit(): keyword = parser.findStringLen(keyword) - keyword = re.sub('\[|\]|\(|\)', '', keyword) + keyword = re.sub(r'\[|\]|\(|\)', '', keyword) if keyword == '0': keyword = input( - paramLen[-1] + - ' not found. Please enter value manually: ') + f'{paramLen[-1]} not found. Please enter value manually: ' + ) stringLen.append(keyword) print("DATA TYPES:", dataTypesOrig) @@ -174,7 +171,7 @@ def findStringLen(self, keyword): print("Data Fields not found in HTML file") # write data to a file - file_split = re.split('/|\.', html_file) + file_split = re.split(r'/|\.', html_file) pickle_file = 'ParameterFiles/' + file_split[-2] with open(pickle_file, 'wb') as pickle_obj: pickle.dump([ diff --git a/Subsystems/cmdGui/Parameter.py b/Subsystems/cmdGui/Parameter.py index 6778075..b069d6b 100644 --- a/Subsystems/cmdGui/Parameter.py +++ b/Subsystems/cmdGui/Parameter.py @@ -34,7 +34,6 @@ class Parameter(QDialog, Ui_Dialog): - # # Initializes Parameter class # @@ -65,12 +64,10 @@ def ProcessSendButton(self): param_list.append(f'{dataType}={input_list[k]}') # --byte=4 k += 1 param_string = ' '.join(param_list) - # print(param_string) launch_string = ( f'{ROOTDIR}/../cmdUtil/cmdUtil --host={pageAddress} ' f'--port={pagePort} --pktid={pagePktId} --endian={pageEndian} ' f'--cmdcode={cmdCode} {param_string.strip()}') - # print launch_string cmd_args = shlex.split(launch_string) subprocess.Popen(cmd_args) self.status_box.setText('Command sent!') @@ -80,7 +77,6 @@ def ProcessSendButton(self): # Main method # if __name__ == '__main__': - # # Initializes variables # diff --git a/Subsystems/cmdGui/UdpCommands.py b/Subsystems/cmdGui/UdpCommands.py index f520aa9..b5a96ed 100644 --- a/Subsystems/cmdGui/UdpCommands.py +++ b/Subsystems/cmdGui/UdpCommands.py @@ -47,9 +47,6 @@ class SubsystemCommands(QDialog, Ui_GenericCommandDialog): - - # pktCount = 0 - # # Init the class # @@ -71,7 +68,7 @@ def checkParams(idx): pf = f'{ROOTDIR}/ParameterFiles/{param_files[idx]}' try: with open(pf, 'rb') as po: - _, paramNames, _, _, _, _ = pickle.load(po) + paramNames = pickle.load(po)[1] return len(paramNames) > 0 # if has parameters except IOError: return False @@ -120,7 +117,6 @@ def usage(): # Main # if __name__ == '__main__': - # # Set defaults for the arguments # diff --git a/Subsystems/tlmGUI/EventMessage.py b/Subsystems/tlmGUI/EventMessage.py index 9d05702..c067f75 100644 --- a/Subsystems/tlmGUI/EventMessage.py +++ b/Subsystems/tlmGUI/EventMessage.py @@ -205,10 +205,6 @@ def usage(): if not subscription or len(subscription.split('.')) < 3: subscription = "GroundSystem" - # arr = subscription.split('.') - # if len(arr) < 3: - # subscription = 'GroundSystem' - print('Event Messages Page started. Subscribed to', subscription) py_endian = '<' if endian == 'L' else '>' diff --git a/Subsystems/tlmGUI/GenericTelemetry.py b/Subsystems/tlmGUI/GenericTelemetry.py index 3510daf..7d7252b 100644 --- a/Subsystems/tlmGUI/GenericTelemetry.py +++ b/Subsystems/tlmGUI/GenericTelemetry.py @@ -36,7 +36,6 @@ class SubsystemTelemetry(QDialog, Ui_GenericTelemetryDialog): - # # Init the class # @@ -77,7 +76,8 @@ def initGTTlmReceiver(self, subscr): self.thread.start() # - # This method processes packets. Called when the TelemetryReceiver receives a message/packet + # This method processes packets. + # Called when the TelemetryReceiver receives a message/packet # def processPendingDatagrams(self, datagram): # diff --git a/Subsystems/tlmGUI/TelemetrySystem.py b/Subsystems/tlmGUI/TelemetrySystem.py index 4c9ce23..1e02aa4 100644 --- a/Subsystems/tlmGUI/TelemetrySystem.py +++ b/Subsystems/tlmGUI/TelemetrySystem.py @@ -22,7 +22,6 @@ import csv import getopt import shlex -# import socket import subprocess import sys from pathlib import Path @@ -38,7 +37,6 @@ class TelemetrySystem(QDialog, Ui_TelemetrySystemDialog): - # # Init the class # @@ -70,8 +68,6 @@ def strToHex(aString): # Dump the telemetry packet # def dumpPacket(self, packetData): - # appIdString = f"{ord(packetData[0]):02X}" - # appIdString += f"{ord(packetData[1]):02X}" appId = (ord(packetData[0]) << 8) + (ord(packetData[1])) print("\n-----------------------------------------------") print("\nPacket: App ID =", hex(appId))