You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
11 KiB
290 lines
11 KiB
# components/uart/uart_ui.py
|
|
# One-file UART page: dedicated handler + UI (no base_handler, no protocol_ui).
|
|
|
|
from PyQt6.QtWidgets import (
|
|
QWidget,
|
|
QVBoxLayout,
|
|
QHBoxLayout,
|
|
QPushButton,
|
|
QComboBox,
|
|
QLineEdit,
|
|
QSplitter,
|
|
)
|
|
from PyQt6.QtCore import Qt
|
|
|
|
# project-local deps (unchanged)
|
|
from components.console.console_ui import console_widget
|
|
from components.console.console_registry import log_main_console
|
|
import components.items.elements as elements
|
|
from components.commands.command_table_ui import command_table_widget
|
|
import config.config as config
|
|
|
|
# UART logic + dialogs + db (unchanged)
|
|
from components.uart.uart_logic import UART_logic
|
|
from components.uart.uart_command_editor import UartCommandEditorDialog
|
|
from components.data import db
|
|
|
|
|
|
# -----------------------------
|
|
# Internal, dedicated UART handler
|
|
# -----------------------------
|
|
# -----------------------------
|
|
# Thin handler that calls back into the UI widget
|
|
# -----------------------------
|
|
class UartHandler:
|
|
"""
|
|
Used by command_table_widget. It doesn't own UART logic.
|
|
It just forwards actions to the parent UartWidget.
|
|
"""
|
|
|
|
def __init__(self, widget: "UartWidget"):
|
|
self.w = widget # back-reference to the UI
|
|
|
|
# table may request the list via the handler
|
|
def get_command_list(self):
|
|
return self.w.uart_logic.get_predefined_commands()
|
|
|
|
# ----- actions triggered from the command table -----
|
|
def send_command(self, command: dict):
|
|
# command has "hex_string"
|
|
self.w.send_command(command)
|
|
|
|
# command editor ops (invoked from command table)
|
|
def add_command(self):
|
|
dialog = UartCommandEditorDialog()
|
|
if dialog.exec():
|
|
command = dialog.get_data()
|
|
db.add_uart_command(command)
|
|
|
|
def modify_command(self, command):
|
|
dialog = UartCommandEditorDialog(command=command)
|
|
if dialog.exec():
|
|
updated_command = dialog.get_data()
|
|
updated_command["id"] = command["id"]
|
|
db.modify_uart_command(updated_command)
|
|
|
|
def delete_command(self, command):
|
|
db.delete_uart_command(command)
|
|
|
|
|
|
# -----------------------------
|
|
# UART UI (layout preserved)
|
|
# -----------------------------
|
|
class UartWidget(QWidget):
|
|
"""
|
|
Drops in where your old ProtocolUIWidget(UART) was used.
|
|
Same controls, same enable/disable behavior, same splitter/table/console layout.
|
|
"""
|
|
|
|
def __init__(self, parent=None):
|
|
super().__init__(parent)
|
|
self.uart_logic = UART_logic() # all comms live here
|
|
self.handler = UartHandler(self) # thin handler for table actions
|
|
self.commands = self.uart_logic.get_predefined_commands()
|
|
self.comboboxes = {}
|
|
self.connection_status = False
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
# === Top Control Row ===
|
|
top_controls = QWidget()
|
|
top_controls_layout = QHBoxLayout(top_controls)
|
|
top_controls_layout.setContentsMargins(0, 0, 0, 0)
|
|
top_controls_layout.setSpacing(12)
|
|
top_controls_layout.setAlignment(Qt.AlignmentFlag.AlignTop)
|
|
|
|
# Dynamically create comboboxes based on handler configuration
|
|
# Static definition instead of get_combobox_config()
|
|
self.comboboxes["port"] = QComboBox()
|
|
self.comboboxes["port"].addItems(self.uart_logic.get_channels())
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("Port", self.comboboxes["port"])
|
|
)
|
|
# Refresh button
|
|
self.button_refresh = elements.create_icon_button(
|
|
config.REFRESH_BUTTON_ICON_LINK, icon_size=30, border_size=4
|
|
)
|
|
top_controls_layout.addWidget(self.button_refresh)
|
|
|
|
self.comboboxes["baudrate"] = QComboBox()
|
|
self.comboboxes["baudrate"].addItems(self.uart_logic.get_baud_rates())
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("Baudrate", self.comboboxes["baudrate"])
|
|
)
|
|
|
|
self.comboboxes["data_bits"] = QComboBox()
|
|
self.comboboxes["data_bits"].addItems(self.uart_logic.get_data_bits())
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("Data Bits", self.comboboxes["data_bits"])
|
|
)
|
|
|
|
self.comboboxes["stop_bits"] = QComboBox()
|
|
self.comboboxes["stop_bits"].addItems(self.uart_logic.get_stop_bits())
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("Stop Bits", self.comboboxes["stop_bits"])
|
|
)
|
|
|
|
self.comboboxes["parity"] = QComboBox()
|
|
self.comboboxes["parity"].addItems(self.uart_logic.get_parity())
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("Parity", self.comboboxes["parity"])
|
|
)
|
|
|
|
# Connect / Disconnect
|
|
self.button_connect = QPushButton("Connect")
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("", self.button_connect)
|
|
)
|
|
|
|
self.button_disconnect = QPushButton("Disconnect")
|
|
top_controls_layout.addWidget(
|
|
elements.label_and_widget("", self.button_disconnect)
|
|
)
|
|
|
|
# === Command Table ===
|
|
self.command_table = command_table_widget(
|
|
commands=self.commands,
|
|
handler=self.handler, # table uses handler methods for send/CRUD
|
|
)
|
|
|
|
col1_widget = QWidget()
|
|
col1_layout = QVBoxLayout(col1_widget)
|
|
col1_layout.setContentsMargins(0, 0, 0, 0)
|
|
col1_layout.setSpacing(4)
|
|
col1_layout.addWidget(self.command_table)
|
|
|
|
# === Input Field + Send Button ===
|
|
self.input_hex = QLineEdit()
|
|
self.button_send_raw = QPushButton("Send Raw")
|
|
|
|
input_line_layout = QHBoxLayout()
|
|
input_line_layout.setContentsMargins(0, 0, 0, 0)
|
|
input_line_layout.setSpacing(4)
|
|
input_line_layout.addWidget(self.input_hex)
|
|
input_line_layout.addWidget(self.button_send_raw)
|
|
|
|
# === Console ===
|
|
self.console = console_widget()
|
|
self.uart_logic.set_logger(self.console.log)
|
|
|
|
console_stack_widget = QWidget()
|
|
console_stack_layout = QVBoxLayout(console_stack_widget)
|
|
console_stack_layout.setContentsMargins(0, 0, 0, 0)
|
|
console_stack_layout.setSpacing(4)
|
|
console_stack_layout.addLayout(input_line_layout)
|
|
console_stack_layout.addWidget(self.console)
|
|
|
|
# === Horizontal Splitter: Table | Console (sizes preserved) ===
|
|
splitter = QSplitter(Qt.Orientation.Horizontal)
|
|
splitter.addWidget(col1_widget)
|
|
splitter.addWidget(console_stack_widget)
|
|
splitter.setSizes([740, 1200])
|
|
splitter.setStretchFactor(0, 0)
|
|
splitter.setStretchFactor(1, 1)
|
|
|
|
# === Main Layout ===
|
|
main_layout = QVBoxLayout()
|
|
main_layout.setContentsMargins(4, 4, 4, 4)
|
|
main_layout.setSpacing(6)
|
|
main_layout.addWidget(top_controls)
|
|
main_layout.addWidget(splitter, stretch=1)
|
|
self.setLayout(main_layout)
|
|
|
|
# === Signals ===
|
|
self.button_refresh.clicked.connect(self.refresh)
|
|
self.button_connect.clicked.connect(self.connect)
|
|
self.button_disconnect.clicked.connect(self.disconnect)
|
|
self.button_send_raw.clicked.connect(self.send_command_raw)
|
|
|
|
self.disconnected_enable_status()
|
|
|
|
# ---- UI state toggles (unchanged) ----
|
|
def disconnected_enable_status(self):
|
|
for combo in self.comboboxes.values():
|
|
elements.set_enabled_state(True, combo, grayOut=False)
|
|
|
|
elements.set_enabled_state(True, self.command_table, grayOut=False)
|
|
elements.set_enabled_state(False, self.input_hex, grayOut=True)
|
|
elements.set_enabled_state(False, self.button_send_raw, grayOut=True)
|
|
elements.set_enabled_state(False, self.button_disconnect, grayOut=True)
|
|
elements.set_enabled_state(True, self.button_connect, grayOut=False)
|
|
|
|
def connected_enable_status(self):
|
|
for combo in self.comboboxes.values():
|
|
elements.set_enabled_state(False, combo, grayOut=True)
|
|
|
|
elements.set_enabled_state(True, self.command_table, grayOut=False)
|
|
elements.set_enabled_state(True, self.input_hex, grayOut=False)
|
|
elements.set_enabled_state(True, self.button_send_raw, grayOut=False)
|
|
elements.set_enabled_state(True, self.button_disconnect, grayOut=False)
|
|
elements.set_enabled_state(False, self.button_connect, grayOut=True)
|
|
|
|
# ---- Button handlers (unchanged behavior) ----
|
|
def connect(self):
|
|
log_main_console("info", "🔗 Connecting...")
|
|
port = self.comboboxes["port"].currentText()
|
|
baudrate = int(self.comboboxes["baudrate"].currentText())
|
|
data_bits = int(self.comboboxes["data_bits"].currentText())
|
|
stop_bits = float(self.comboboxes["stop_bits"].currentText())
|
|
parity = self.comboboxes["parity"].currentText()[0].upper()
|
|
success = self.uart_logic.connect(
|
|
port=port,
|
|
baudrate=baudrate,
|
|
data_bits=data_bits,
|
|
stop_bits=stop_bits,
|
|
parity=parity,
|
|
)
|
|
if success:
|
|
self.connected_enable_status()
|
|
self.command_table.set_connected_state()
|
|
self.connection_status = True
|
|
else:
|
|
elements.flash_button(
|
|
self.button_connect, flash_style="background-color: red;"
|
|
)
|
|
|
|
def disconnect(self):
|
|
log_main_console("info", "🔌 Disconnecting...")
|
|
success = self.uart_logic.disconnect()
|
|
if success:
|
|
log_main_console("info", "🔌 Disconnecting...")
|
|
self.disconnected_enable_status()
|
|
self.command_table.set_disconnected_state()
|
|
self.connection_status = False
|
|
self.refresh(silent=True)
|
|
else:
|
|
elements.flash_button(
|
|
self.button_disconnect, flash_style="background-color: red;"
|
|
)
|
|
|
|
def refresh(self, silent: bool = False):
|
|
log_main_console("info", "🔄 Refreshing...")
|
|
self.comboboxes["port"].clear()
|
|
port = self.uart_logic.get_channels()
|
|
if port:
|
|
self.comboboxes["port"].addItems(port)
|
|
if not silent:
|
|
elements.flash_button(self.button_refresh)
|
|
log_main_console("success", "🔄 Refresehd")
|
|
else:
|
|
elements.flash_button(
|
|
self.button_refresh, flash_style="background-color: red;"
|
|
)
|
|
log_main_console("error", "🔄 Refresehd")
|
|
|
|
def get_current_config(self):
|
|
return {key: cb.currentText() for key, cb in self.comboboxes.items()}
|
|
|
|
def send_command(self, command):
|
|
# self.uart_logic.send_command(command["hex_string"])
|
|
self.uart_logic.send_pgkomm2(command["hex_string"])
|
|
config.CURRENT_COMMAND = command["name"]
|
|
|
|
def send_command_raw(self):
|
|
hex_str = self.input_hex.text().strip()
|
|
if not hex_str:
|
|
self.console.log("warning", "⚠️ No command entered.")
|
|
else:
|
|
self.uart_logic.send_command(hex_str)
|
|
config.CURRENT_COMMAND = hex_str
|