This commit is contained in:
david rice
2026-01-07 16:01:52 +00:00
parent a5c2f1c140
commit d4c124ff1a
6 changed files with 105 additions and 156 deletions

149
main.py
View File

@@ -5,16 +5,18 @@ AUTOMOTIVE POWER SIMULATOR APP - MAIN.PY
VERSION: 1.0 VERSION: 1.0
AUTHOR: D. RICE 14/11/2025 AUTHOR: D. RICE 06/01/2026
© 2025 ARRIVE © 2026 ARRIVE
""" """
# Imports # Imports
import sys import sys
from PySide6.QtWidgets import (QApplication, QDialog, QMainWindow) from PySide6.QtWidgets import (QApplication, QDialog, QMainWindow)
from PySide6.QtCore import (QThread, QObject, Signal, Slot) from PySide6.QtCore import (QThread, QObject, Signal, Slot)
from PySide6.QtSerialPort import (QserialPort, QSerialPortInfo)
import time import time
import struct
from ui_mainwindow import Ui_MainWindow from ui_mainwindow import Ui_MainWindow
from ui_scanning import Ui_scanningDialog from ui_scanning import Ui_scanningDialog
@@ -73,16 +75,16 @@ class MainWindow(QMainWindow):
self.ui.connButton.clicked.connect(self.conn_button_press) self.ui.connButton.clicked.connect(self.conn_button_press)
# Set initial size # Set initial size
initial_width = 1024 initial_width = 1000
initial_height = 768 initial_height = 600
# Lock the window size by setting min/max to the same values # Lock the window size by setting min/max to the same values
self.setMinimumSize(initial_width, initial_height) self.setMinimumSize(initial_width, initial_height)
self.setMaximumSize(initial_width, initial_height) self.setMaximumSize(initial_width, initial_height)
self.setGeometry(0, 0, 1024, 768) self.setGeometry(0, 0, 1000, 600)
self.setFixedSize(1024, 768) self.setFixedSize(1000, 600)
self.show() self.show()
@@ -100,8 +102,16 @@ class MainWindow(QMainWindow):
QApplication.processEvents() QApplication.processEvents()
# Run Connection actions here # Setup serial port
#self.start_worker()
ser = self.serial.Serial(port="/dev/ttyACM0", baudrate=921600)
command = 73 #0x49 'I' ASCII
state = 0
data = (command, state)
byte_data = self.pack_integers_to_bytes(*data)
while ((IDN_Response_flag == False) and (Error_flag == False)): while ((IDN_Response_flag == False) and (Error_flag == False)):
QApplication.processEvents() QApplication.processEvents()
@@ -138,100 +148,39 @@ class MainWindow(QMainWindow):
QApplication.processEvents() QApplication.processEvents()
def pack_integers_to_bytes(self, *integers: int) -> bytes:
# Setup header
sync_bytes = [0x41, 0x52]
# Process data
# Mask each input to 8-bits to prevent packing errors
data_bytes = [i & 0xFF for i in integers]
# Get length
data_length = [len(data_bytes) & 0xFF]
# Calculate checksum
# Summingall data bytes, then applying bitwise NOT
total_sum = sum(data_bytes)
rx_checksum = ~total_sum
rx_checksum_h = (rx_checksum >> 8) & 0xFF
rx_checksum_l = rx_checksum & 0xFF
checksum_bytes = [rx_checksum_h,rx_checksum_l]
# Combine all components
full_packet = sync_bytes + data_length + data_bytes + checksum_bytes
# Dymanically create format string
# '!' = Network order, 'B' = unsigned char
# We need as many 'B's as there are elements in the full packet
format_string = f"!{len(full_packet)}B"
return struct.pack(format_string, *full_packet)
def run_scope_setup (self): def run_scope_setup (self):
self.worker.run_setup() self.worker.run_setup()
@Slot()
def start_worker(self):
# Create a QThread
self.worker_thread = QThread()
#nCreate the worker QObject (Now created directly, no import needed)
self.worker = ScopeWorker()
# Move the worker object to the thread
self.worker.moveToThread(self.worker_thread)
# Connect Signals
self.worker_thread.started.connect(self.worker.run)
self.worker.idn_signal.connect(self.handle_idn)
self.worker.data_ready_signal.connect(self.handle_data_ready)
self.worker.error_signal.connect(self.handle_error)
# Clean-up connections
self.worker.finished_signal.connect(self.worker_thread.quit)
self.worker.finished_signal.connect(self.worker.deleteLater)
self.worker_thread.finished.connect(self.worker_thread.deleteLater)
# Start the QThread, which triggers worker.run
self.worker_thread.start()
@Slot()
def signal_acquisition(self):
"""Sends the signal to the worker to start pulling data."""
if self.worker:
self.log_text.append("Main: Sending START_ACQUISITION signal.")
self.status_label.setText("Status: Acquiring data...")
# This is safe because start_acquisition only sets a flag
self.worker.start_acquisition()
# --- SLOTS: Receive data safely from the worker thread ---
@Slot(str)
def handle_idn(self, idn_string):
global IDN_Response_flag
global Error_flag
# Received the initial IDN from the worker
IDN_Response_flag = True
# Split the string by the comma delimiter
components = idn_string.strip().split(',')
# Split the string by the comma delimiter
components = idn_string.strip().split(',')
if len(components) == 4:
# Assign the components to meaningful keys in a dictionary
parsed_data = {
"manufacturer": components[0],
"model": components[1],
"serial_number": components[2],
"firmware_version": components[3]
}
self.ui.manu.setText(parsed_data.get("manufacturer"))
self.ui.model.setText(parsed_data.get("model"))
self.ui.sn.setText(parsed_data.get("serial_number"))
self.ui.fw.setText(parsed_data.get("firmware_version"))
else:
Error_flag = True
self.ui.manu.setText("---")
self.ui.model.setText("---")
self.ui.sn.setText("---")
self.ui.fw.setText("---")
@Slot(str)
def handle_data_ready(self, data_snippet):
"""Received the acquired data from the worker."""
self.status_label.setText("Status: Data Ready. Waiting for next command.")
self.log_text.append(f"Main: Received Waveform Data Snippet:\n{data_snippet}")
@Slot(str)
def handle_error(self, message):
global Error_flag
Error_flag = True
def closeEvent(self):
"""Handle application close to stop the thread gracefully."""
if self.worker_thread and self.worker_thread.isRunning():
self.worker.stop()
# Wait a moment for the thread to clean up
self.worker_thread.wait(500)
# Run main # Run main
if __name__ == '__main__': if __name__ == '__main__':

View File

@@ -13,7 +13,7 @@ class Ui_MainWindow(object):
MainWindow.setToolButtonStyle(Qt.ToolButtonIconOnly) MainWindow.setToolButtonStyle(Qt.ToolButtonIconOnly)
MainWindow.setAnimated(True) MainWindow.setAnimated(True)
MainWindow.setDocumentMode(False) MainWindow.setDocumentMode(False)
MainWindow.setWindowIcon(QIcon('/home/davidrice/Python/Automotive-Power-Simulator-App/arriveico.png')) MainWindow.setWindowIcon(QIcon('/home/david-rice/Python/Automotive-Power-Simulator-App/arriveico.png'))
fontmain = QFont() fontmain = QFont()
fontmain.setFamilies([u"Optimism Sans"]) fontmain.setFamilies([u"Optimism Sans"])
fontmain.setPointSize(8) fontmain.setPointSize(8)
@@ -21,7 +21,7 @@ class Ui_MainWindow(object):
MainWindow.setFont(fontmain) MainWindow.setFont(fontmain)
# Ensure the path is correct for your system! # Ensure the path is correct for your system!
image_path = "/home/davidrice/Python/Automotive-Power-Simulator-App/appbackground.jpg" # Example Path image_path = "/home/david-rice/Python/Automotive-Power-Simulator-App/appbackground.jpg" # Example Path
# --- Define and Apply the Style Sheet --- # --- Define and Apply the Style Sheet ---
bg_style_sheet = f""" bg_style_sheet = f"""
@@ -37,7 +37,7 @@ class Ui_MainWindow(object):
self.centralwidget.setStyleSheet(bg_style_sheet) self.centralwidget.setStyleSheet(bg_style_sheet)
self.header = QLabel(self.centralwidget) self.header = QLabel(self.centralwidget)
self.header.setObjectName(u"header") self.header.setObjectName(u"header")
self.header.setGeometry(QRect(50, 35, 650, 50)) self.header.setGeometry(QRect(50, 35, 750, 50))
font = QFont() font = QFont()
font.setFamilies([u"Optimism Sans"]) font.setFamilies([u"Optimism Sans"])
font.setPointSize(24) font.setPointSize(24)
@@ -49,7 +49,7 @@ class Ui_MainWindow(object):
self.test_area = QFrame(self.centralwidget) self.test_area = QFrame(self.centralwidget)
self.test_area.setObjectName(u"test_area") self.test_area.setObjectName(u"test_area")
self.test_area.setGeometry(QRect(50, 115, 924, 618)) self.test_area.setGeometry(QRect(50, 115, 900, 440))
self.test_area.setFrameShape(QFrame.StyledPanel) self.test_area.setFrameShape(QFrame.StyledPanel)
self.test_area.setFrameShadow(QFrame.Raised) self.test_area.setFrameShadow(QFrame.Raised)
@@ -63,7 +63,7 @@ class Ui_MainWindow(object):
self.connButton = QPushButton(self.test_area) self.connButton = QPushButton(self.test_area)
self.connButton.setObjectName(u"connButton") self.connButton.setObjectName(u"connButton")
self.connButton.setGeometry(QRect(25, 25, 125, 25)) self.connButton.setGeometry(QRect(350, 25, 200, 25))
self.connButton.setStyleSheet(button_style) self.connButton.setStyleSheet(button_style)
text_label_style = """ text_label_style = """
@@ -75,11 +75,11 @@ class Ui_MainWindow(object):
} }
""" """
self.manuLabel = QLabel(self.test_area) #self.manuLabel = QLabel(self.test_area)
self.manuLabel.setObjectName(u"manuLabel") #self.manuLabel.setObjectName(u"manuLabel")
self.manuLabel.setGeometry(QRect(200, 5, 250, 15)) #self.manuLabel.setGeometry(QRect(200, 5, 250, 15))
self.manuLabel.setAlignment(Qt.AlignCenter) #self.manuLabel.setAlignment(Qt.AlignCenter)
self.manuLabel.setStyleSheet(text_label_style) #self.manuLabel.setStyleSheet(text_label_style)
label_style = """ label_style = """
QLabel { QLabel {
@@ -90,47 +90,47 @@ class Ui_MainWindow(object):
} }
""" """
self.manu = QLabel(self.test_area) #self.manu = QLabel(self.test_area)
self.manu.setObjectName(u"manu") #self.manu.setObjectName(u"manu")
self.manu.setGeometry(QRect(200, 25, 250, 25)) #self.manu.setGeometry(QRect(200, 25, 250, 25))
self.manu.setAlignment(Qt.AlignCenter) #self.manu.setAlignment(Qt.AlignCenter)
self.manu.setStyleSheet(label_style) #self.manu.setStyleSheet(label_style)
self.modelLabel = QLabel(self.test_area) #self.modelLabel = QLabel(self.test_area)
self.modelLabel.setObjectName(u"modelLabel") #self.modelLabel.setObjectName(u"modelLabel")
self.modelLabel.setGeometry(QRect(475, 5, 125, 15)) #self.modelLabel.setGeometry(QRect(475, 5, 125, 15))
self.modelLabel.setAlignment(Qt.AlignCenter) #self.modelLabel.setAlignment(Qt.AlignCenter)
self.modelLabel.setStyleSheet(text_label_style) #self.modelLabel.setStyleSheet(text_label_style)
self.model = QLabel(self.test_area) #self.model = QLabel(self.test_area)
self.model.setObjectName(u"model") #self.model.setObjectName(u"model")
self.model.setGeometry(QRect(475, 25, 125, 25)) #self.model.setGeometry(QRect(475, 25, 125, 25))
self.model.setAlignment(Qt.AlignCenter) #self.model.setAlignment(Qt.AlignCenter)
self.model.setStyleSheet(label_style) #self.model.setStyleSheet(label_style)
self.snLabel = QLabel(self.test_area) #self.snLabel = QLabel(self.test_area)
self.snLabel.setObjectName(u"snlabel") #self.snLabel.setObjectName(u"snlabel")
self.snLabel.setGeometry(QRect(625, 5, 125, 15)) #self.snLabel.setGeometry(QRect(625, 5, 125, 15))
self.snLabel.setAlignment(Qt.AlignCenter) #self.snLabel.setAlignment(Qt.AlignCenter)
self.snLabel.setStyleSheet(text_label_style) #self.snLabel.setStyleSheet(text_label_style)
self.sn = QLabel(self.test_area) #self.sn = QLabel(self.test_area)
self.sn.setObjectName(u"sn") #self.sn.setObjectName(u"sn")
self.sn.setGeometry(QRect(625, 25, 125, 25)) #self.sn.setGeometry(QRect(625, 25, 125, 25))
self.sn.setAlignment(Qt.AlignCenter) #self.sn.setAlignment(Qt.AlignCenter)
self.sn.setStyleSheet(label_style) #self.sn.setStyleSheet(label_style)
self.fwLabel = QLabel(self.test_area) #self.fwLabel = QLabel(self.test_area)
self.fwLabel.setObjectName(u"fwLabel") #self.fwLabel.setObjectName(u"fwLabel")
self.fwLabel.setGeometry(QRect(775, 5, 125, 15)) #self.fwLabel.setGeometry(QRect(775, 5, 125, 15))
self.fwLabel.setAlignment(Qt.AlignCenter) #self.fwLabel.setAlignment(Qt.AlignCenter)
self.fwLabel.setStyleSheet(text_label_style) #self.fwLabel.setStyleSheet(text_label_style)
self.fw = QLabel(self.test_area) #self.fw = QLabel(self.test_area)
self.fw.setObjectName(u"fw") #self.fw.setObjectName(u"fw")
self.fw.setGeometry(QRect(775, 25, 125, 25)) #self.fw.setGeometry(QRect(775, 25, 125, 25))
self.fw.setAlignment(Qt.AlignCenter) #self.fw.setAlignment(Qt.AlignCenter)
self.fw.setStyleSheet(label_style) #self.fw.setStyleSheet(label_style)
frame_style = """ frame_style = """
@@ -157,14 +157,14 @@ class Ui_MainWindow(object):
None)) None))
self.header.setText(QCoreApplication.translate("MainWindow", u"AUTOMOTIVE POWER SIMULATOR", None)) self.header.setText(QCoreApplication.translate("MainWindow", u"AUTOMOTIVE POWER SIMULATOR", None))
self.connButton.setText(QCoreApplication.translate("MainWindow", u"CONNECT", None)) self.connButton.setText(QCoreApplication.translate("MainWindow", u"CONNECT", None))
self.manuLabel.setText(QCoreApplication.translate("MainWindow", u"MANUFACTURER", None)) #self.manuLabel.setText(QCoreApplication.translate("MainWindow", u"MANUFACTURER", None))
self.manu.setText(QCoreApplication.translate("MainWindow", u"---", None)) #self.manu.setText(QCoreApplication.translate("MainWindow", u"---", None))
self.modelLabel.setText(QCoreApplication.translate("MainWindow", u"MODEL", None)) #self.modelLabel.setText(QCoreApplication.translate("MainWindow", u"MODEL", None))
self.model.setText(QCoreApplication.translate("MainWindow", u"---", None)) #self.model.setText(QCoreApplication.translate("MainWindow", u"---", None))
self.snLabel.setText(QCoreApplication.translate("MainWindow", u"SERIAL NO", None)) #self.snLabel.setText(QCoreApplication.translate("MainWindow", u"SERIAL NO", None))
self.sn.setText(QCoreApplication.translate("MainWindow", u"---", None)) #self.sn.setText(QCoreApplication.translate("MainWindow", u"---", None))
self.fwLabel.setText(QCoreApplication.translate("MainWindow", u"F/W REV", None)) #self.fwLabel.setText(QCoreApplication.translate("MainWindow", u"F/W REV", None))
self.fw.setText(QCoreApplication.translate("MainWindow", u"---", None)) #self.fw.setText(QCoreApplication.translate("MainWindow", u"---", None))
# retranslateUi # retranslateUi

View File

@@ -6,7 +6,7 @@ class Ui_scanningDialog(object):
def setupUi(self, Dialog): def setupUi(self, Dialog):
if not Dialog.objectName(): if not Dialog.objectName():
Dialog.setObjectName(u"Dialog") Dialog.setObjectName(u"Dialog")
Dialog.resize(320, 160) Dialog.resize(300, 150)
# Set the window flags to remove the title bar # Set the window flags to remove the title bar
Dialog.setWindowFlags(Qt.WindowType.FramelessWindowHint) Dialog.setWindowFlags(Qt.WindowType.FramelessWindowHint)
@@ -19,7 +19,7 @@ class Ui_scanningDialog(object):
self.label = QLabel(Dialog) self.label = QLabel(Dialog)
self.label.setObjectName(u"label") self.label.setObjectName(u"label")
self.label.setFont(font) self.label.setFont(font)
self.label.setGeometry(QRect(10, 10, 300, 140)) self.label.setGeometry(QRect(10, 10, 280, 130))
self.label.setAlignment(Qt.AlignCenter) self.label.setAlignment(Qt.AlignCenter)
self.label.setWordWrap(True) self.label.setWordWrap(True)
@@ -37,5 +37,5 @@ class Ui_scanningDialog(object):
# setupUi # setupUi
def retranslateUi(self, Dialog): def retranslateUi(self, Dialog):
self.label.setText(QCoreApplication.translate("Dialog", u"SCANNING FOR DSO80204B", None)) self.label.setText(QCoreApplication.translate("Dialog", u"SCANNING FOR ARRIVE POWERSIM", None))
# retranslateUi # retranslateUi