diff --git a/.gitignore b/.gitignore index 9c79f62..54ef51d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,6 @@ *.pyc cmdUtil +!/Subsystems/cmdUtil +CMakeFiles +CMakeCache.txt .DS_Store diff --git a/GroundSystem.py b/GroundSystem.py index 059a0b9..f72a52a 100644 --- a/GroundSystem.py +++ b/GroundSystem.py @@ -17,7 +17,7 @@ # See the License for the specific language governing permissions and # limitations under the License. # -#cFS Ground System Version 2.0.0 +# cFS Ground System Version 2.0.0 # #!/usr/bin/env python3 # @@ -28,8 +28,14 @@ from PyQt5.QtWidgets import QApplication, QMainWindow, QMessageBox -from MainWindow import Ui_MainWindow from RoutingService import RoutingService +from Ui_MainWindow import Ui_MainWindow + +from _version import __version__ as _version +from _version import _version_string + +__version__ = _version + ROOTDIR = Path(sys.argv[0]).resolve().parent @@ -38,18 +44,25 @@ # CFS Ground System: Setup and manage the main window # class GroundSystem(QMainWindow, Ui_MainWindow): + HDR_VER_1_OFFSET = 0 + HDR_VER_2_OFFSET = 4 + # # Init the class # def __init__(self): super().__init__() - self.setupUi((self)) + self.setupUi(self) self.RoutingService = None self.alert = QMessageBox() self.pushButtonStartTlm.clicked.connect(self.startTlmSystem) self.pushButtonStartCmd.clicked.connect(self.startCmdSystem) + self.cbTlmHeaderVer.currentIndexChanged.connect(self.setTlmOffset) + self.cbCmdHeaderVer.currentIndexChanged.connect(self.setCmdOffsets) + for sb in (self.sbTlmOffset, self.sbCmdOffsetPri, self.sbCmdOffsetSec): + sb.valueChanged.connect(self.saveOffsets) # Init lists self.ipAddressesList = ['All'] self.spacecraftNames = ['All'] @@ -81,14 +94,12 @@ def DisplayErrorMessage(self, message): # Start the telemetry system for the selected spacecraft def startTlmSystem(self): + # Setup the subscription (to let the telemetry + # system know the messages it will be receiving) + subscription = '--sub=GroundSystem' selectedSpacecraft = self.getSelectedSpacecraftName() - - # Setup the subscription (to let know the - # telemetry system the messages it will be receiving) - if selectedSpacecraft == 'All': - subscription = '--sub=GroundSystem' - else: - subscription = f'--sub=GroundSystem.{selectedSpacecraft}.TelemetryPackets' + if selectedSpacecraft != 'All': + subscription += f'.{selectedSpacecraft}.TelemetryPackets' # Open Telemetry System system_call = f'python3 {ROOTDIR}/Subsystems/tlmGUI/TelemetrySystem.py {subscription}' @@ -114,6 +125,37 @@ def startFDLSystem(self): subscription ]) + def setTlmOffset(self): + selectedVer = self.cbTlmHeaderVer.currentText().strip() + if selectedVer == "Custom": + self.sbTlmOffset.setEnabled(True) + else: + self.sbTlmOffset.setEnabled(False) + if selectedVer == "1": + self.sbTlmOffset.setValue(self.HDR_VER_1_OFFSET) + elif selectedVer == "2": + self.sbTlmOffset.setValue(self.HDR_VER_2_OFFSET) + + def setCmdOffsets(self): + selectedVer = self.cbCmdHeaderVer.currentText().strip() + if selectedVer == "Custom": + self.sbCmdOffsetPri.setEnabled(True) + self.sbCmdOffsetSec.setEnabled(True) + else: + self.sbCmdOffsetPri.setEnabled(False) + self.sbCmdOffsetSec.setEnabled(False) + if selectedVer == "1": + self.sbCmdOffsetPri.setValue(self.HDR_VER_1_OFFSET) + elif selectedVer == "2": + self.sbCmdOffsetPri.setValue(self.HDR_VER_2_OFFSET) + self.sbCmdOffsetSec.setValue(self.HDR_VER_1_OFFSET) + + def saveOffsets(self): + offsets = bytes((self.sbTlmOffset.value(), self.sbCmdOffsetPri.value(), + self.sbCmdOffsetSec.value())) + with open("/tmp/OffsetData", "wb") as f: + f.write(offsets) + # Update the combo box list in gui def updateIpList(self, ip, name): self.ipAddressesList.append(ip) @@ -131,7 +173,10 @@ def initRoutingService(self): # Main # if __name__ == "__main__": - + + # Report Version Number upon startup + print(_version_string) + # Init app app = QApplication(sys.argv) @@ -144,6 +189,7 @@ def initRoutingService(self): # Start the Routing Service MainWindow.initRoutingService() + MainWindow.saveOffsets() # Execute the app sys.exit(app.exec_()) diff --git a/MainWindow.ui b/MainWindow.ui index 0999d2e..3a8cdfe 100644 --- a/MainWindow.ui +++ b/MainWindow.ui @@ -9,8 +9,8 @@ 0 0 - 420 - 217 + 552 + 305 @@ -25,7 +25,7 @@ - + 22 @@ -49,21 +49,8 @@ - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - + + @@ -78,14 +65,14 @@ - Selected IP Address: + Selected IP Address - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + @@ -106,18 +93,137 @@ - - - - Qt::Horizontal + + + + + 0 + 0 + + + + + 169 + 0 + + + + Tlm header version + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter - + + + + + - 40 - 20 + 132 + 0 + + + + + 132 + 16777215 - + + + 1 + + + + + 2 + + + + + Custom + + + + + + + + Cmd header version + + + + + + + false + + + <html><head/><body><p>Offset (in bytes) to be <span style=" font-weight:600;">added to</span> existing offsets listed in telemetry text files</p></body></html> + + + QAbstractSpinBox::NoButtons + + + + + + + false + + + <html><head/><body><p>Offset (in bytes) to be added <span style=" font-weight:600;">after</span> the <span style=" font-weight:600;">primary</span> header in a command packet</p></body></html> + + + QAbstractSpinBox::NoButtons + + + + + + + + 1 + + + + + 2 + + + + + Custom + + + + + + + + false + + + <html><head/><body><p>Offset (in bytes) to be added <span style=" font-weight:600;">after</span> the <span style=" font-weight:600;">secondary</span> header in a command packet</p></body></html> + + + QAbstractSpinBox::NoButtons + + + + + + + Offsets + + + + + + + (Hover for info) + + diff --git a/README.md b/README.md index 645d0fd..907abc1 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,13 @@ See [Guide-GroundSystem.md](https://github.com/nasa/cFS-GroundSystem/blob/master ## Version History +### Development Build: 2.1.0+dev76 + +- Fixes more lgtm warnings +- Allows users to change the byte offsets for sending commands and parsing telemetry, to support different header versions or other implementations of cFS +- Adds a file to store version information and reports version upon ground-system startup. +- See + ### Development Build: 2.1.12 - Change all individual UI elements to table widgets. Update backend code accordingly diff --git a/RoutingService.py b/RoutingService.py index 47139ca..c5447ff 100644 --- a/RoutingService.py +++ b/RoutingService.py @@ -100,8 +100,7 @@ def run(self): # Handle errors except socket.error: - print( - f'Ignored socket error for attempt {socketErrorCount}') + print('Ignored socket error for attempt', socketErrorCount) socketErrorCount += 1 sleep(1) diff --git a/Subsystems/cmdGui/CommandSystem.py b/Subsystems/cmdGui/CommandSystem.py index 01ad4a2..b858d1c 100644 --- a/Subsystems/cmdGui/CommandSystem.py +++ b/Subsystems/cmdGui/CommandSystem.py @@ -29,8 +29,10 @@ from PyQt5.QtWidgets import (QApplication, QDialog, QHeaderView, QPushButton, QTableWidgetItem) +from MiniCmdUtil import MiniCmdUtil from Ui_CommandSystemDialog import Ui_CommandSystemDialog +## ../cFS/tools/cFS-GroundSystem/Subsystems/cmdGui/ ROOTDIR = Path(sys.argv[0]).resolve().parent @@ -43,6 +45,7 @@ def __init__(self): super().__init__() self.setupUi(self) self.move(800, 100) + self.mcu = None # # Processes 'Display Page' button @@ -91,15 +94,25 @@ def ProcessQuickButton(self, idx): f'--port={quickPort[qIdx]} ' f'--pktid={pktId} --endian={quickEndian[qIdx]} ' f'--cmdcode={quickCode[qIdx]} --file={quickParam[qIdx]}') + cmd_args = shlex.split(launch_string) + subprocess.Popen(cmd_args) # if doesn't require parameters else: - launch_string = ( - f'{ROOTDIR}/../cmdUtil/cmdUtil ' - f'--host=\"{address}\" --port={quickPort[qIdx]} ' - f'--pktid={pktId} --endian={quickEndian[qIdx]} ' - f'--cmdcode={quickCode[qIdx]}') - cmd_args = shlex.split(launch_string) - subprocess.Popen(cmd_args) + self.mcu = MiniCmdUtil(address, quickPort[qIdx], + quickEndian[qIdx], pktId, + quickCode[qIdx]) + sendSuccess = self.mcu.sendPacket() + print("Command sent successfully:", sendSuccess) + # launch_string = ( + # f'{ROOTDIR.parent}/cmdUtil/cmdUtil ' + # f'--host=\"{address}\" --port={quickPort[qIdx]} ' + # f'--pktid={pktId} --endian={quickEndian[qIdx]} ' + # f'--cmdcode={quickCode[qIdx]}') + + def closeEvent(self, event): + if self.mcu: + self.mcu.mm.close() + super().closeEvent(event) # @@ -166,7 +179,7 @@ def ProcessQuickButton(self, idx): with open(f'{ROOTDIR}/{quickDefFile}') as subFile: reader = csv.reader(subFile) for fileRow in reader: - if fileRow[0][0] != '#': + if not fileRow[0].startswith('#'): subsys.append(fileRow[0]) subsysFile.append(fileRow[1]) quickCmd.append(fileRow[2].strip()) diff --git a/Subsystems/cmdGui/MiniCmdUtil.py b/Subsystems/cmdGui/MiniCmdUtil.py new file mode 100644 index 0000000..360b82c --- /dev/null +++ b/Subsystems/cmdGui/MiniCmdUtil.py @@ -0,0 +1,153 @@ +# +# GSC-18128-1, "Core Flight Executive Version 6.7" +# +# Copyright (c) 2006-2019 United States Government as represented by +# the Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +## This file is a Python implementation of a subset of functions in cmdUtil +## to support the GroundSystem GUI + +import mmap +import socket +from collections import namedtuple + + +class MiniCmdUtil: + ## Class objects + sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + TypeSignature = namedtuple("TypeSignature", 'byteLen, signed, endian') + dataTypes = { + ("b", "int8", "byte"): TypeSignature(1, True, None), + ("m", "uint8"): TypeSignature(1, False, None), + ("h", "int16", "half"): TypeSignature(2, True, None), + ("n", "uint16"): TypeSignature(2, False, None), + ("l", "int32", "long", "word"): TypeSignature(4, True, None), + ("o", "uint32"): TypeSignature(4, False, None), + ("q", "int64"): TypeSignature(8, True, None), + ("p", "uint64"): TypeSignature(8, False, None), + ("i", "int16b"): TypeSignature(2, True, "big"), + ("j", "int32b"): TypeSignature(4, True, "big"), + ("k", "int64b"): TypeSignature(8, True, "big"), + ("w", "uint16b"): TypeSignature(2, False, "big"), + ("x", "uint32b"): TypeSignature(4, False, "big"), + ("y", "uint64b"): TypeSignature(8, False, "big") + } + + def __init__(self, + host="127.0.0.1", + port=1234, + endian="BE", + pktID=0, + cmdCode=0, + parameters=None): + + self.host = host + self.port = int(port) + self.endian = "big" if endian == "BE" else "little" + self.pktID = int(pktID, 16) + self.cmdCode = int(cmdCode) + self.parameters = parameters + self.payload = bytearray() + self.packet = bytearray() + with open("/tmp/OffsetData", "r+b") as f: + self.mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) + + self.cmdOffsetPri = 0 + self.cmdOffsetSec = 0 + self.checksum = 0xFF + self.cfsCmdSecHdr = bytearray(2) + + def assemblePriHeader(self): + ccsdsPri = bytearray(6) + ccsdsPri[:2] = self.pktID.to_bytes(2, byteorder='big') + ccsdsPri[2:4] = (0xC000).to_bytes(2, byteorder='big') + totalPacketLen = len(ccsdsPri) + len(self.cfsCmdSecHdr) + self.assemblePayload() + totalPacketLen += len(self.payload) + totalPacketLen += self.cmdOffsetPri + self.cmdOffsetSec + ccsdsPri[4:] = (totalPacketLen - 7).to_bytes(2, byteorder="big") + return ccsdsPri + + def assemblePayload(self): + if self.parameters: + paramList = self.parameters.split(" ") + for param in paramList: + items = param.split("=") ## e.g. ["--uint16", "2"] + if "--string" not in param: ## non-string param + dataType = items[0].strip("-") ## Remove "--" prefix + dataVal = int(items[1]) + for key in self.dataTypes: ## Loop thru dictionary keys + if dataType in key: ## Check if e.g. "uint16" in key tuple + ## Get the TypeSignature tuple + typeSig = self.dataTypes[key] + break ## Stop checking dictionary + ## If TypeSignature endian is None, get the + ## user-provided/default endian. Otherwise get + ## the TypeSignature endian + endian = typeSig.endian or self.endian + ## Convert to bytes of correct length, endianess, and sign + dataValB = dataVal.to_bytes(typeSig.byteLen, + byteorder=endian, + signed=typeSig.signed) + ## Add data to payload bytearray + self.payload.extend(dataValB) + else: + stringParams = items[1].strip("\"").split( + ":") ## e.g. ["16", "ES_APP"] + ## Zero init'd bytearray of length e.g. 16 + fixedLenStr = bytearray(int(stringParams[0])) + stringB = stringParams[1].encode( + ) ## Param string to bytes + ## Insert param bytes into front of bytearray + fixedLenStr[:len(stringB)] = stringB + ## Add data to payload bytearray + self.payload.extend(fixedLenStr) + + def assemblePacket(self): + self._getOffsets() + priHeader = self.assemblePriHeader() + self.packet.extend(priHeader) + priOffset = bytearray(self.cmdOffsetPri) + self.packet.extend(priOffset) + self.cfsCmdSecHdr[0] = self.cmdCode + secOffset = bytearray(self.cmdOffsetSec) + for b in b''.join((priHeader, priOffset, self.cfsCmdSecHdr, secOffset, + self.payload)): + self.checksum ^= b + self.cfsCmdSecHdr[1] = self.checksum + self.packet.extend(self.cfsCmdSecHdr) + self.packet.extend(secOffset) + self.packet.extend(self.payload) + self.checksum = 0xFF + + def sendPacket(self): + self.assemblePacket() + print("Data to send:") + for i, v in enumerate(self.packet): + print(f"0x{format(v, '02X')}", end=" ") + if (i + 1) % 8 == 0: + print() + print() + bytesSent = self.sock.sendto(self.packet, (self.host, self.port)) + return bytesSent > 0 + + def _getOffsets(self): + try: + self.cmdOffsetPri = self.mm[1] + self.cmdOffsetSec = self.mm[2] + except ValueError: + pass diff --git a/Subsystems/cmdGui/Parameter.py b/Subsystems/cmdGui/Parameter.py index 1cd6d9d..d17688a 100644 --- a/Subsystems/cmdGui/Parameter.py +++ b/Subsystems/cmdGui/Parameter.py @@ -30,6 +30,7 @@ QTableWidgetItem) from HTMLDocsParser import HTMLDocsParser +from MiniCmdUtil import MiniCmdUtil from Ui_ParameterDialog import Ui_Dialog ROOTDIR = Path(sys.argv[0]).resolve().parent @@ -45,6 +46,7 @@ def __init__(self): self.parser = HTMLDocsParser() self.setWindowTitle("Parameter Dialog") self.SendButton_1.clicked.connect(self.ProcessSendButton) + self.mcu = None # # Button method @@ -63,13 +65,24 @@ def ProcessSendButton(self): else: param_list.append(f'{dataType}={inpt}') # --byte=4 param_string = ' '.join(param_list) - launch_string = ( - f'{ROOTDIR}/../cmdUtil/cmdUtil --host={pageAddress} ' - f'--port={pagePort} --pktid={pagePktId} --endian={pageEndian} ' - f'--cmdcode={cmdCode} {param_string.strip()}') - cmd_args = shlex.split(launch_string) - subprocess.Popen(cmd_args) - self.status_box.setText('Command sent!') + self.mcu = MiniCmdUtil(pageAddress, pagePort, pageEndian, pagePktId, + cmdCode, param_string.strip()) + sendSuccess = self.mcu.sendPacket() + # launch_string = ( + # f'{ROOTDIR.parent}/cmdUtil/cmdUtil --host={pageAddress} ' + # f'--port={pagePort} --pktid={pagePktId} --endian={pageEndian} ' + # f'--cmdcode={cmdCode} {param_string.strip()}')result + # cmd_args = shlex.split(launch_string) + # subprocess.Popen(cmd_args) + if sendSuccess: + self.status_box.setText('Command sent!') + else: + self.status_box.setText('Error occured') + + def closeEvent(self, event): + if self.mcu: + self.mcu.mm.close() + super().closeEvent(event) # @@ -98,7 +111,7 @@ def ProcessSendButton(self): elif opt in ("-d", "--descrip"): cmdDesc = arg # command name, eg No-Op elif opt in ("-i", "--idx"): - _ = int(arg) # comand index in command definition file + _ = int(arg) # command index in command definition file elif opt in ("-h", "--host"): pageAddress = arg # send to address elif opt in ("-p", "--port"): @@ -124,7 +137,7 @@ def ProcessSendButton(self): # pickle_file = f'{ROOTDIR}/ParameterFiles/' + re.split(r'\.', param_file)[0] with open(pickle_file, 'rb') as pickle_obj: - dataTypesOrig, paramNames, paramLen, paramDesc, dataTypesNew, stringLen = pickle.load( + _, paramNames, _, paramDesc, dataTypesNew, stringLen = pickle.load( pickle_obj) # diff --git a/Subsystems/cmdGui/UdpCommands.py b/Subsystems/cmdGui/UdpCommands.py index ba02561..e3758c5 100644 --- a/Subsystems/cmdGui/UdpCommands.py +++ b/Subsystems/cmdGui/UdpCommands.py @@ -42,8 +42,10 @@ from PyQt5.QtWidgets import (QApplication, QDialog, QHeaderView, QPushButton, QTableWidgetItem) +from MiniCmdUtil import MiniCmdUtil from Ui_GenericCommandDialog import Ui_GenericCommandDialog +## ../cFS/tools/cFS-GroundSystem/Subsystems/cmdGui/ ROOTDIR = Path(sys.argv[0]).resolve().parent class SubsystemCommands(QDialog, Ui_GenericCommandDialog): @@ -54,6 +56,7 @@ def __init__(self): super().__init__() self.setupUi(self) self.setWindowTitle(pageTitle) + self.mcu = None # for j in range(self.tblCommands.rowCount()): # btn = self.tblCommands.cellWidget(j, 1) @@ -89,16 +92,23 @@ def ProcessSendButtonGeneric(self, idx): f'--host=\"{address}\" --port={pagePort} ' f'--pktid={pagePktId} --endian={pageEndian} ' f'--cmdcode={cmdCodes[idx]} --file={param_files[idx]}') - + cmd_args = shlex.split(launch_string) + subprocess.Popen(cmd_args) # If parameters not required, directly calls cmdUtil to send command else: - launch_string = ( - f'{ROOTDIR}/../cmdUtil/cmdUtil --host=\"{address}\" ' - f'--port={pagePort} --pktid={pagePktId} ' - f'--endian={pageEndian} --cmdcode={cmdCodes[idx]}') - - cmd_args = shlex.split(launch_string) - subprocess.Popen(cmd_args) + self.mcu = MiniCmdUtil(address, pagePort, pageEndian, + pagePktId, cmdCodes[idx]) + sendSuccess = self.mcu.sendPacket() + print("Command sent successfully:", sendSuccess) + # launch_string = ( + # f'{ROOTDIR.parent}/cmdUtil/cmdUtil --host=\"{address}\" ' + # f'--port={pagePort} --pktid={pagePktId} ' + # f'--endian={pageEndian} --cmdcode={cmdCodes[idx]}') + + def closeEvent(self, event): + if self.mcu: + self.mcu.mm.close() + super().closeEvent(event) # diff --git a/Subsystems/tlmGUI/EventMessage.py b/Subsystems/tlmGUI/EventMessage.py index 22297ec..d24c602 100644 --- a/Subsystems/tlmGUI/EventMessage.py +++ b/Subsystems/tlmGUI/EventMessage.py @@ -24,46 +24,36 @@ # The EVS Event Message has the following format # # -# ES HK format: -# -# Packet Header -# uint16 StreamId; 0 -# uint16 Sequence; 2 -# uint16 Length; 4 - -# Tlm Secondary Header -# uint32 seconds 6 -# uint16 subseconds 10 +# Packet Header Start Byte +# uint16 StreamId; 0 +# uint16 Sequence; 2 +# uint16 Length; 4 -# Packet data -# -# Event format: -# -# Packet Header -# uint16 StreamId; -# uint16 Sequence; -# uint16 Length; +# Start byte values after primary header depend +# on header version. +# Add 4 to ALL the values below if header version 2 -# Tlm Secondary Header -# uint32 seconds -# uint16 subseconds +# Tlm Secondary Header Start Byte +# uint32 seconds 6 +# uint16 subseconds 10 # Packet ID -# char AppName[20] -# uint16 EventID; -# uint16 EventType; -# uint32 SpacecraftID; -# uint32 ProcessorID; +# char AppName[20] 12 +# uint16 EventID; 32 +# uint16 EventType; 34 +# uint32 SpacecraftID; 36 +# uint32 ProcessorID; 40 # Message -# char Message[122]; -# uint8 Spare1; -# uint8 Spare2; +# char Message[122]; 44 +# uint8 Spare1; 166 +# uint8 Spare2; 167 import getopt +import mmap import sys -from struct import unpack from pathlib import Path +from struct import unpack import zmq from PyQt5.QtCore import QThread, pyqtSignal @@ -87,6 +77,9 @@ def __init__(self, aid): 4: "CRITICAL" } + with open("/tmp/OffsetData", "r+b") as f: + self.mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) + def initEMTlmReceiver(self, subscr): self.setWindowTitle(f'{pageTitle} for: {subscr}') self.thread = EMTlmReceiver(subscr, self.appId) @@ -107,13 +100,20 @@ def processPendingDatagrams(self, datagram): # # Get App Name, Event ID, Type and Event Text! # - appName = datagram[16:36].decode('utf-8', 'ignore') - eventID = int.from_bytes(datagram[36:38], byteorder='little') - eventType = int.from_bytes(datagram[38:40], byteorder='little') - eventText = datagram[48:].decode('utf-8', 'ignore') + try: + tlmOffset = self.mm[0] + except ValueError: + pass + startByte = 12 + tlmOffset + appName = datagram[startByte:startByte + 20].decode('utf-8', 'ignore') + eventID = int.from_bytes(datagram[startByte + 20:startByte + 22], + byteorder='little') + eventType = int.from_bytes(datagram[startByte + 22:startByte + 24], + byteorder='little') + eventText = datagram[startByte + 32:].decode('utf-8', 'ignore') appName = appName.split("\0")[0] eventText = eventText.split("\0")[0] - eventTypeStr = self.eventTypes.get(eventType, "Invalid Event Type") + eventTypeStr = self.eventTypes.get(eventType, "INVALID EVENT TYPE") eventString = f"EVENT --> {appName}-{eventTypeStr} Event ID: {eventID} : {eventText}" self.eventOutput.appendPlainText(eventString) @@ -188,11 +188,11 @@ def usage(): usage() sys.exit() if opt in ("-p", "--port"): - _ = arg + pass elif opt in ("-t", "--title"): pageTitle = arg elif opt in ("-f", "--file"): - _ = arg + pass elif opt in ("-a", "--appid"): appId = arg elif opt in ("-e", "--endian"): diff --git a/Subsystems/tlmGUI/GenericTelemetry.py b/Subsystems/tlmGUI/GenericTelemetry.py index 53cf7fc..235ec49 100644 --- a/Subsystems/tlmGUI/GenericTelemetry.py +++ b/Subsystems/tlmGUI/GenericTelemetry.py @@ -19,9 +19,9 @@ # #!/usr/bin/env python3 # - import csv import getopt +import mmap import sys from pathlib import Path from struct import unpack @@ -33,8 +33,10 @@ from Ui_GenericTelemetryDialog import Ui_GenericTelemetryDialog +## ../cFS/tools/cFS-GroundSystem/Subsystems/tlmGUI ROOTDIR = Path(sys.argv[0]).resolve().parent + class SubsystemTelemetry(QDialog, Ui_GenericTelemetryDialog): # # Init the class @@ -42,28 +44,40 @@ class SubsystemTelemetry(QDialog, Ui_GenericTelemetryDialog): def __init__(self): super().__init__() self.setupUi(self) + with open("/tmp/OffsetData", "r+b") as f: + self.mm = mmap.mmap(f.fileno(), 0, prot=mmap.PROT_READ) # - # This method Decodes a telemetry item from the packet and displays it + # This method decodes a telemetry item from the packet and displays it # - @staticmethod - def displayTelemetryItem(datagram, tlmIndex, labelField, valueField): + def displayTelemetryItem(self, datagram, tlmIndex, labelField, valueField): if tlmItemIsValid[tlmIndex]: + try: + tlmOffset = self.mm[0] + except ValueError: + pass TlmField1 = tlmItemFormat[tlmIndex] if TlmField1[0] == "<": TlmField1 = TlmField1[1:] - TlmField2 = datagram[int(tlmItemStart[tlmIndex]):( - int(tlmItemStart[tlmIndex]) + int(tlmItemSize[tlmIndex]))] - TlmField = unpack(TlmField1, TlmField2) - if tlmItemDisplayType[tlmIndex] == 'Dec': - valueField.setText(str(TlmField[0])) - elif tlmItemDisplayType[tlmIndex] == 'Hex': - valueField.setText(hex(TlmField[0])) - elif tlmItemDisplayType[tlmIndex] == 'Enm': - valueField.setText(tlmItemEnum[tlmIndex][int(TlmField[0])]) - elif tlmItemDisplayType[tlmIndex] == 'Str': - valueField.setText(TlmField[0].decode('utf-8', 'ignore')) - labelField.setText(tlmItemDesc[tlmIndex]) + try: + itemStart = int(tlmItemStart[tlmIndex]) + tlmOffset + except UnboundLocalError: + pass + TlmField2 = datagram[itemStart:itemStart + + int(tlmItemSize[tlmIndex])] + if TlmField2: + TlmField = unpack(TlmField1, TlmField2) + if tlmItemDisplayType[tlmIndex] == 'Dec': + valueField.setText(str(TlmField[0])) + elif tlmItemDisplayType[tlmIndex] == 'Hex': + valueField.setText(hex(TlmField[0])) + elif tlmItemDisplayType[tlmIndex] == 'Enm': + valueField.setText(tlmItemEnum[tlmIndex][int(TlmField[0])]) + elif tlmItemDisplayType[tlmIndex] == 'Str': + valueField.setText(TlmField[0].decode('utf-8', 'ignore')) + labelField.setText(tlmItemDesc[tlmIndex]) + else: + print("ERROR: Can't unpack buffer of length", len(TlmField2)) # Start the telemetry receiver (see GTTlmReceiver class) def initGTTlmReceiver(self, subscr): @@ -99,6 +113,7 @@ def processPendingDatagrams(self, datagram): def closeEvent(self, event): self.thread.runs = False self.thread.wait(2000) + self.mm.close() super().closeEvent(event) @@ -167,7 +182,7 @@ def usage(): usage() sys.exit() elif opt in ("-p", "--port"): - _ = arg + pass elif opt in ("-t", "--title"): pageTitle = arg elif opt in ("-f", "--file"): @@ -184,7 +199,7 @@ def usage(): print('Generic Telemetry Page started. Subscribed to', subscription) - py_endian = '<' if endian == 'L' else '>' + py_endian = '<' if endian.upper() == 'L' else '>' # # Init the QT application and the telemetry class @@ -208,7 +223,7 @@ def usage(): with open(f"{ROOTDIR}/{tlmDefFile}") as tlmfile: reader = csv.reader(tlmfile, skipinitialspace=True) for row in reader: - if not row[0].startswith('#'): + if not row[0].startswith("#"): tlmItemIsValid.append(True) tlmItemDesc.append(row[0]) tlmItemStart.append(row[1]) diff --git a/Subsystems/tlmGUI/GenericTelemetryDialog.ui b/Subsystems/tlmGUI/GenericTelemetryDialog.ui index 4b59f51..f1d2ed2 100644 --- a/Subsystems/tlmGUI/GenericTelemetryDialog.ui +++ b/Subsystems/tlmGUI/GenericTelemetryDialog.ui @@ -6,8 +6,8 @@ 0 0 - 630 - 816 + 574 + 836 @@ -16,9 +16,9 @@ - 90 - 730 - 431 + 29 + 750 + 711 61 @@ -28,29 +28,30 @@ - <html><head/><body><p>*No packets? Remember to select the IP address of your<br/>spacecraft in the Main Window.</p></body></html> + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Noto Sans'; font-size:12pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">*No packets? Remember to select the IP address of<br />your spacecraft in the Main Window.</p></body></html> - 70 - 110 - 470 - 601 + 20 + 100 + 431 + 621 - - Qt::ScrollBarAlwaysOff - - - QAbstractScrollArea::AdjustToContentsOnFirstShow - QAbstractItemView::NoEditTriggers - 225 + 200 + + + false @@ -66,9 +67,9 @@ - 510 - 50 - 81 + 450 + 100 + 100 31 @@ -76,13 +77,13 @@ QDialogButtonBox::Close - + - 270 - 25 + 260 + 24 73 - 60 + 54 @@ -123,10 +124,10 @@ - + - 370 + 350 23 125 62 @@ -167,7 +168,7 @@ - + 42 diff --git a/Subsystems/tlmGUI/Ui_GenericTelemetryDialog.py b/Subsystems/tlmGUI/Ui_GenericTelemetryDialog.py index 9304866..3937700 100644 --- a/Subsystems/tlmGUI/Ui_GenericTelemetryDialog.py +++ b/Subsystems/tlmGUI/Ui_GenericTelemetryDialog.py @@ -11,17 +11,15 @@ class Ui_GenericTelemetryDialog(object): def setupUi(self, GenericTelemetryDialog): GenericTelemetryDialog.setObjectName("GenericTelemetryDialog") - GenericTelemetryDialog.resize(630, 816) + GenericTelemetryDialog.resize(574, 836) self.label_6 = QtWidgets.QLabel(GenericTelemetryDialog) - self.label_6.setGeometry(QtCore.QRect(90, 730, 431, 61)) + self.label_6.setGeometry(QtCore.QRect(29, 750, 711, 61)) font = QtGui.QFont() font.setPointSize(12) self.label_6.setFont(font) self.label_6.setObjectName("label_6") self.tblTelemetry = QtWidgets.QTableWidget(GenericTelemetryDialog) - self.tblTelemetry.setGeometry(QtCore.QRect(70, 110, 470, 601)) - self.tblTelemetry.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) - self.tblTelemetry.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContentsOnFirstShow) + self.tblTelemetry.setGeometry(QtCore.QRect(20, 100, 431, 621)) self.tblTelemetry.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers) self.tblTelemetry.setObjectName("tblTelemetry") self.tblTelemetry.setColumnCount(2) @@ -30,18 +28,19 @@ def setupUi(self, GenericTelemetryDialog): self.tblTelemetry.setHorizontalHeaderItem(0, item) item = QtWidgets.QTableWidgetItem() self.tblTelemetry.setHorizontalHeaderItem(1, item) - self.tblTelemetry.horizontalHeader().setDefaultSectionSize(225) + self.tblTelemetry.horizontalHeader().setDefaultSectionSize(200) + self.tblTelemetry.verticalHeader().setVisible(False) self.buttonBox = QtWidgets.QDialogButtonBox(GenericTelemetryDialog) - self.buttonBox.setGeometry(QtCore.QRect(510, 50, 81, 31)) + self.buttonBox.setGeometry(QtCore.QRect(450, 100, 100, 31)) self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Close) self.buttonBox.setObjectName("buttonBox") - self.widget = QtWidgets.QWidget(GenericTelemetryDialog) - self.widget.setGeometry(QtCore.QRect(270, 25, 73, 60)) - self.widget.setObjectName("widget") - self.verticalLayout = QtWidgets.QVBoxLayout(self.widget) + self.layoutWidget = QtWidgets.QWidget(GenericTelemetryDialog) + self.layoutWidget.setGeometry(QtCore.QRect(260, 24, 73, 54)) + self.layoutWidget.setObjectName("layoutWidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.layoutWidget) self.verticalLayout.setContentsMargins(0, 0, 0, 0) self.verticalLayout.setObjectName("verticalLayout") - self.packetIdLabel = QtWidgets.QLabel(self.widget) + self.packetIdLabel = QtWidgets.QLabel(self.layoutWidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -51,7 +50,7 @@ def setupUi(self, GenericTelemetryDialog): self.packetIdLabel.setMaximumSize(QtCore.QSize(16777215, 25)) self.packetIdLabel.setObjectName("packetIdLabel") self.verticalLayout.addWidget(self.packetIdLabel) - self.packetId = QtWidgets.QLCDNumber(self.widget) + self.packetId = QtWidgets.QLCDNumber(self.layoutWidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) @@ -59,16 +58,16 @@ def setupUi(self, GenericTelemetryDialog): self.packetId.setSizePolicy(sizePolicy) self.packetId.setObjectName("packetId") self.verticalLayout.addWidget(self.packetId) - self.widget1 = QtWidgets.QWidget(GenericTelemetryDialog) - self.widget1.setGeometry(QtCore.QRect(370, 23, 125, 62)) - self.widget1.setObjectName("widget1") - self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.widget1) + self.layoutWidget1 = QtWidgets.QWidget(GenericTelemetryDialog) + self.layoutWidget1.setGeometry(QtCore.QRect(350, 23, 125, 62)) + self.layoutWidget1.setObjectName("layoutWidget1") + self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.layoutWidget1) self.verticalLayout_3.setContentsMargins(0, 0, 0, 0) self.verticalLayout_3.setObjectName("verticalLayout_3") - self.label_5 = QtWidgets.QLabel(self.widget1) + self.label_5 = QtWidgets.QLabel(self.layoutWidget1) self.label_5.setObjectName("label_5") self.verticalLayout_3.addWidget(self.label_5) - self.sequenceCount = QtWidgets.QSpinBox(self.widget1) + self.sequenceCount = QtWidgets.QSpinBox(self.layoutWidget1) self.sequenceCount.setMinimumSize(QtCore.QSize(101, 31)) self.sequenceCount.setMaximumSize(QtCore.QSize(101, 31)) self.sequenceCount.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) @@ -76,16 +75,16 @@ def setupUi(self, GenericTelemetryDialog): self.sequenceCount.setProperty("value", 0) self.sequenceCount.setObjectName("sequenceCount") self.verticalLayout_3.addWidget(self.sequenceCount) - self.widget2 = QtWidgets.QWidget(GenericTelemetryDialog) - self.widget2.setGeometry(QtCore.QRect(42, 24, 204, 62)) - self.widget2.setObjectName("widget2") - self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.widget2) + self.layoutWidget2 = QtWidgets.QWidget(GenericTelemetryDialog) + self.layoutWidget2.setGeometry(QtCore.QRect(42, 24, 204, 62)) + self.layoutWidget2.setObjectName("layoutWidget2") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.layoutWidget2) self.verticalLayout_2.setContentsMargins(0, 0, 0, 0) self.verticalLayout_2.setObjectName("verticalLayout_2") - self.subSystemTelemetryPageLabel = QtWidgets.QLabel(self.widget2) + self.subSystemTelemetryPageLabel = QtWidgets.QLabel(self.layoutWidget2) self.subSystemTelemetryPageLabel.setObjectName("subSystemTelemetryPageLabel") self.verticalLayout_2.addWidget(self.subSystemTelemetryPageLabel) - self.subSystemLineEdit = QtWidgets.QLineEdit(self.widget2) + self.subSystemLineEdit = QtWidgets.QLineEdit(self.layoutWidget2) self.subSystemLineEdit.setMinimumSize(QtCore.QSize(141, 31)) self.subSystemLineEdit.setMaximumSize(QtCore.QSize(141, 31)) self.subSystemLineEdit.setReadOnly(True) @@ -99,7 +98,11 @@ def setupUi(self, GenericTelemetryDialog): def retranslateUi(self, GenericTelemetryDialog): _translate = QtCore.QCoreApplication.translate GenericTelemetryDialog.setWindowTitle(_translate("GenericTelemetryDialog", "Telemetry Page")) - self.label_6.setText(_translate("GenericTelemetryDialog", "

*No packets? Remember to select the IP address of your
spacecraft in the Main Window.

")) + self.label_6.setText(_translate("GenericTelemetryDialog", "\n" +"\n" +"

*No packets? Remember to select the IP address of
your spacecraft in the Main Window.

")) item = self.tblTelemetry.horizontalHeaderItem(0) item.setText(_translate("GenericTelemetryDialog", "Telemetry Point Label")) item = self.tblTelemetry.horizontalHeaderItem(1) diff --git a/MainWindow.py b/Ui_MainWindow.py similarity index 51% rename from MainWindow.py rename to Ui_MainWindow.py index dea718d..d020d3f 100644 --- a/MainWindow.py +++ b/Ui_MainWindow.py @@ -2,19 +2,17 @@ # Form implementation generated from reading ui file '/home/lbleier/cFS/tools/cFS-GroundSystem/MainWindow.ui' # -# Created by: PyQt5 UI code generator 5.12.3 +# Created by: PyQt5 UI code generator 5.10.1 # # WARNING! All changes made in this file will be lost! - from PyQt5 import QtCore, QtGui, QtWidgets - class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.setEnabled(True) - MainWindow.resize(420, 217) + MainWindow.resize(552, 305) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(24) sizePolicy.setVerticalStretch(0) @@ -24,24 +22,22 @@ def setupUi(self, MainWindow): self.centralwidget.setObjectName("centralwidget") self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) self.verticalLayout.setObjectName("verticalLayout") - self.labelHomeTittle = QtWidgets.QLabel(self.centralwidget) + self.labelHomeTitle = QtWidgets.QLabel(self.centralwidget) font = QtGui.QFont() font.setPointSize(22) font.setBold(False) font.setWeight(50) - self.labelHomeTittle.setFont(font) - self.labelHomeTittle.setAlignment(QtCore.Qt.AlignCenter) - self.labelHomeTittle.setObjectName("labelHomeTittle") - self.verticalLayout.addWidget(self.labelHomeTittle) + self.labelHomeTitle.setFont(font) + self.labelHomeTitle.setAlignment(QtCore.Qt.AlignCenter) + self.labelHomeTitle.setObjectName("labelHomeTitle") + self.verticalLayout.addWidget(self.labelHomeTitle) self.line_2 = QtWidgets.QFrame(self.centralwidget) self.line_2.setFrameShape(QtWidgets.QFrame.HLine) self.line_2.setFrameShadow(QtWidgets.QFrame.Sunken) self.line_2.setObjectName("line_2") self.verticalLayout.addWidget(self.line_2) - self.horizontalLayout = QtWidgets.QHBoxLayout() - self.horizontalLayout.setObjectName("horizontalLayout") - spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem) + self.gridLayout = QtWidgets.QGridLayout() + self.gridLayout.setObjectName("gridLayout") self.label_3 = QtWidgets.QLabel(self.centralwidget) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) sizePolicy.setHorizontalStretch(0) @@ -49,18 +45,64 @@ def setupUi(self, MainWindow): sizePolicy.setHeightForWidth(self.label_3.sizePolicy().hasHeightForWidth()) self.label_3.setSizePolicy(sizePolicy) self.label_3.setMinimumSize(QtCore.QSize(141, 0)) - self.label_3.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) + self.label_3.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) self.label_3.setObjectName("label_3") - self.horizontalLayout.addWidget(self.label_3) + self.gridLayout.addWidget(self.label_3, 0, 0, 1, 1) self.comboBoxIpAddresses = QtWidgets.QComboBox(self.centralwidget) self.comboBoxIpAddresses.setMinimumSize(QtCore.QSize(132, 0)) self.comboBoxIpAddresses.setMaximumSize(QtCore.QSize(132, 16777215)) self.comboBoxIpAddresses.setObjectName("comboBoxIpAddresses") self.comboBoxIpAddresses.addItem("") - self.horizontalLayout.addWidget(self.comboBoxIpAddresses) - spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) - self.horizontalLayout.addItem(spacerItem1) - self.verticalLayout.addLayout(self.horizontalLayout) + self.gridLayout.addWidget(self.comboBoxIpAddresses, 0, 1, 1, 1) + self.label_4 = QtWidgets.QLabel(self.centralwidget) + sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Preferred) + sizePolicy.setHorizontalStretch(0) + sizePolicy.setVerticalStretch(0) + sizePolicy.setHeightForWidth(self.label_4.sizePolicy().hasHeightForWidth()) + self.label_4.setSizePolicy(sizePolicy) + self.label_4.setMinimumSize(QtCore.QSize(169, 0)) + self.label_4.setAlignment(QtCore.Qt.AlignLeading|QtCore.Qt.AlignLeft|QtCore.Qt.AlignVCenter) + self.label_4.setObjectName("label_4") + self.gridLayout.addWidget(self.label_4, 1, 0, 1, 1) + self.cbTlmHeaderVer = QtWidgets.QComboBox(self.centralwidget) + self.cbTlmHeaderVer.setMinimumSize(QtCore.QSize(132, 0)) + self.cbTlmHeaderVer.setMaximumSize(QtCore.QSize(132, 16777215)) + self.cbTlmHeaderVer.setObjectName("cbTlmHeaderVer") + self.cbTlmHeaderVer.addItem("") + self.cbTlmHeaderVer.addItem("") + self.cbTlmHeaderVer.addItem("") + self.gridLayout.addWidget(self.cbTlmHeaderVer, 1, 1, 1, 1) + self.label_2 = QtWidgets.QLabel(self.centralwidget) + self.label_2.setObjectName("label_2") + self.gridLayout.addWidget(self.label_2, 2, 0, 1, 1) + self.sbTlmOffset = QtWidgets.QSpinBox(self.centralwidget) + self.sbTlmOffset.setEnabled(False) + self.sbTlmOffset.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) + self.sbTlmOffset.setObjectName("sbTlmOffset") + self.gridLayout.addWidget(self.sbTlmOffset, 1, 2, 1, 1) + self.sbCmdOffsetPri = QtWidgets.QSpinBox(self.centralwidget) + self.sbCmdOffsetPri.setEnabled(False) + self.sbCmdOffsetPri.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) + self.sbCmdOffsetPri.setObjectName("sbCmdOffsetPri") + self.gridLayout.addWidget(self.sbCmdOffsetPri, 2, 2, 1, 1) + self.cbCmdHeaderVer = QtWidgets.QComboBox(self.centralwidget) + self.cbCmdHeaderVer.setObjectName("cbCmdHeaderVer") + self.cbCmdHeaderVer.addItem("") + self.cbCmdHeaderVer.addItem("") + self.cbCmdHeaderVer.addItem("") + self.gridLayout.addWidget(self.cbCmdHeaderVer, 2, 1, 1, 1) + self.sbCmdOffsetSec = QtWidgets.QSpinBox(self.centralwidget) + self.sbCmdOffsetSec.setEnabled(False) + self.sbCmdOffsetSec.setButtonSymbols(QtWidgets.QAbstractSpinBox.NoButtons) + self.sbCmdOffsetSec.setObjectName("sbCmdOffsetSec") + self.gridLayout.addWidget(self.sbCmdOffsetSec, 2, 3, 1, 1) + self.label = QtWidgets.QLabel(self.centralwidget) + self.label.setObjectName("label") + self.gridLayout.addWidget(self.label, 0, 2, 1, 1) + self.label_6 = QtWidgets.QLabel(self.centralwidget) + self.label_6.setObjectName("label_6") + self.gridLayout.addWidget(self.label_6, 0, 3, 1, 1) + self.verticalLayout.addLayout(self.gridLayout) self.horizontalLayout_2 = QtWidgets.QHBoxLayout() self.horizontalLayout_2.setSpacing(32) self.horizontalLayout_2.setObjectName("horizontalLayout_2") @@ -112,10 +154,24 @@ def setupUi(self, MainWindow): def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "Main Window")) - self.labelHomeTittle.setText(_translate("MainWindow", "CFS Ground System")) - self.label_3.setText(_translate("MainWindow", "Selected IP Address: ")) + self.labelHomeTitle.setText(_translate("MainWindow", "CFS Ground System")) + self.label_3.setText(_translate("MainWindow", "Selected IP Address")) self.comboBoxIpAddresses.setItemText(0, _translate("MainWindow", "All")) + self.label_4.setText(_translate("MainWindow", "Tlm header version")) + self.cbTlmHeaderVer.setItemText(0, _translate("MainWindow", "1")) + self.cbTlmHeaderVer.setItemText(1, _translate("MainWindow", "2")) + self.cbTlmHeaderVer.setItemText(2, _translate("MainWindow", "Custom")) + self.label_2.setText(_translate("MainWindow", "Cmd header version")) + self.sbTlmOffset.setToolTip(_translate("MainWindow", "

Offset (in bytes) to be added to existing offsets listed in telemetry text files

")) + self.sbCmdOffsetPri.setToolTip(_translate("MainWindow", "

Offset (in bytes) to be added after the primary header in a command packet

")) + self.cbCmdHeaderVer.setItemText(0, _translate("MainWindow", "1")) + self.cbCmdHeaderVer.setItemText(1, _translate("MainWindow", "2")) + self.cbCmdHeaderVer.setItemText(2, _translate("MainWindow", "Custom")) + self.sbCmdOffsetSec.setToolTip(_translate("MainWindow", "

Offset (in bytes) to be added after the secondary header in a command packet

")) + self.label.setText(_translate("MainWindow", "Offsets")) + self.label_6.setText(_translate("MainWindow", "(Hover for info)")) self.pushButtonStartTlm.setText(_translate("MainWindow", "Start Telemetry System")) self.pushButtonStartCmd.setText(_translate("MainWindow", "Start Command System")) self.label_5.setText(_translate("MainWindow", "*Read Guide-GroundSystem.txt for help")) self.pushButton.setText(_translate("MainWindow", "Close")) + diff --git a/_version.py b/_version.py new file mode 100644 index 0000000..6704991 --- /dev/null +++ b/_version.py @@ -0,0 +1,49 @@ +# +# GSC-18128-1, "Core Flight Executive Version 6.7" +# +# Copyright (c) 2006-2019 United States Government as represented by +# the Administrator of the National Aeronautics and Space Administration. +# All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +# Development Build Macro Definitions +_cFS_GrndSys_build_number = 76 +_cFS_GrndSys_build_baseline = "v2.1.0" + +# Version Number Definitions +# ONLY APPLY for OFFICIAL release builds +_cFS_GrndSys_MAJOR = 2 +_cFS_GrndSys_MINOR = 1 +_cFS_GrndSys_REVISION = 0 +_cFS_GrndSys_MISSIONREV = 0 + +# Development Build format for __version__ +# Baseline git tag + Number of commits since baseline +__version__ = "+dev".join((_cFS_GrndSys_build_baseline,str(_cFS_GrndSys_build_number))) + +# Development Build format for __version_string__ +_version_string = " cFS-GroundSystem Development Build\n " + __version__ + " (Codename: Bootes)" + +# Use the following templates for Official Releases ONLY + + # Official Release format for __version__ + # __version__ = ".".join(map(str,(_cFS_GrndSys_MAJOR, _cFS_GrndSys_MINOR, _cFS_GrndSys_REVISION, _cFS_GrndSys_MISSIONREV))) + + # Official Release format for _version_string + # _version_string = " cFS-GroundSystem v" + __version__ + +# END TEMPLATES +