210 lines
7.6 KiB
Python
210 lines
7.6 KiB
Python
import sys
|
|
from PySide6.QtSerialPort import QSerialPortInfo
|
|
from PySide6.QtWidgets import *
|
|
from PySide6.QtCore import *
|
|
from PySide6.QtGui import *
|
|
|
|
from pysetterminal.rawprotocol import RawProtocol, RawProtocolWidget
|
|
from pysetterminal.serialbus import SerialBus, SerialTab
|
|
|
|
|
|
|
|
class MainWindow(QMainWindow):
|
|
"""Главное окно приложения"""
|
|
|
|
def __init__(self):
|
|
super().__init__()
|
|
# Создаем низкоуровневый протокол
|
|
self.raw_protocol = RawProtocol()
|
|
# Создаем высокоуровневый протокол, передавая ему low-level
|
|
self.serial_bus = SerialBus(self.raw_protocol)
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
self.setWindowTitle("Терминал")
|
|
self.setGeometry(100, 100, 800, 600)
|
|
|
|
# Главный виджет и компоновка
|
|
main_widget = QWidget()
|
|
main_layout = QVBoxLayout()
|
|
|
|
# Центральный виджет с вкладками
|
|
self.tab_widget = QTabWidget()
|
|
|
|
# Виджет для RAW протокола (всегда внизу)
|
|
self.raw_widget = RawProtocolWidget(self.raw_protocol)
|
|
|
|
# Вкладка для серийной шины
|
|
self.serial_tab = SerialTab(self.serial_bus, self.raw_protocol, self.raw_widget)
|
|
self.tab_widget.addTab(self.serial_tab, "Серийная шина")
|
|
|
|
main_layout.addWidget(self.tab_widget)
|
|
|
|
main_layout.addWidget(self.raw_widget)
|
|
|
|
main_widget.setLayout(main_layout)
|
|
self.setCentralWidget(main_widget)
|
|
|
|
# Создание меню
|
|
self.create_menu()
|
|
|
|
# Создание панели инструментов
|
|
self.create_toolbar()
|
|
|
|
def create_menu(self):
|
|
menubar = self.menuBar()
|
|
|
|
# Меню Файл
|
|
file_menu = menubar.addMenu("Файл")
|
|
|
|
exit_action = QAction("Выход", self)
|
|
exit_action.triggered.connect(self.close)
|
|
file_menu.addAction(exit_action)
|
|
|
|
# Меню Помощь
|
|
help_menu = menubar.addMenu("Помощь")
|
|
|
|
protocol_action = QAction("Информация о протоколе", self)
|
|
protocol_action.triggered.connect(self.show_protocol_info)
|
|
help_menu.addAction(protocol_action)
|
|
|
|
def create_toolbar(self):
|
|
toolbar = self.addToolBar("Подключение")
|
|
|
|
# Выбор COM порта
|
|
toolbar.addWidget(QLabel("COM порт:"))
|
|
|
|
self.port_combo = QComboBox()
|
|
self.port_combo.setMinimumWidth(150)
|
|
self.refresh_ports()
|
|
toolbar.addWidget(self.port_combo)
|
|
|
|
# Кнопка обновления портов
|
|
refresh_btn = QToolButton()
|
|
refresh_btn.setText("⟳")
|
|
refresh_btn.setToolTip("Обновить список портов")
|
|
refresh_btn.clicked.connect(self.refresh_ports)
|
|
toolbar.addWidget(refresh_btn)
|
|
|
|
# Кнопка подключения/отключения
|
|
self.connect_btn = QPushButton("Подключить")
|
|
self.connect_btn.clicked.connect(self.toggle_connection)
|
|
toolbar.addWidget(self.connect_btn)
|
|
|
|
# Индикатор статуса
|
|
self.status_label = QLabel("Отключено")
|
|
self.status_label.setStyleSheet("color: red;")
|
|
toolbar.addWidget(self.status_label)
|
|
|
|
toolbar.addSeparator()
|
|
|
|
# Настройки скорости
|
|
toolbar.addWidget(QLabel("Скорость:"))
|
|
self.baud_combo = QComboBox()
|
|
self.baud_combo.addItems(["9600", "19200", "38400", "57600", "115200", "230400", "460800", "921600"])
|
|
self.baud_combo.setCurrentText("115200")
|
|
toolbar.addWidget(self.baud_combo)
|
|
|
|
def refresh_ports(self):
|
|
"""Обновление списка доступных COM портов"""
|
|
self.port_combo.clear()
|
|
ports = QSerialPortInfo.availablePorts()
|
|
for port in ports:
|
|
self.port_combo.addItem(f"{port.portName()} - {port.description()}")
|
|
|
|
if not ports:
|
|
self.port_combo.addItem("Порты не найдены")
|
|
|
|
def toggle_connection(self):
|
|
"""Подключение/отключение от COM порта"""
|
|
if self.raw_protocol.is_connected:
|
|
# Отключение
|
|
self.raw_protocol.disconnect()
|
|
self.connect_btn.setText("Подключить")
|
|
self.status_label.setText("Отключено")
|
|
self.status_label.setStyleSheet("color: red;")
|
|
|
|
# Блокировка элементов управления
|
|
self.serial_tab.bus_write_btn.setEnabled(False)
|
|
self.serial_tab.bus_read_btn.setEnabled(False)
|
|
self.raw_widget.raw_send_btn.setEnabled(False)
|
|
self.raw_widget.raw_read_btn.setEnabled(False)
|
|
else:
|
|
# Подключение
|
|
port_text = self.port_combo.currentText()
|
|
if " - " in port_text:
|
|
port_name = port_text.split(" - ")[0]
|
|
else:
|
|
port_name = port_text
|
|
|
|
try:
|
|
baudrate = int(self.baud_combo.currentText())
|
|
if self.raw_protocol.connect(port_name, baudrate):
|
|
self.connect_btn.setText("Отключить")
|
|
self.status_label.setText("Подключено")
|
|
self.status_label.setStyleSheet("color: green;")
|
|
|
|
# Разблокировка элементов управления
|
|
self.serial_tab.bus_write_btn.setEnabled(True)
|
|
self.serial_tab.bus_read_btn.setEnabled(True)
|
|
self.raw_widget.raw_send_btn.setEnabled(True)
|
|
self.raw_widget.raw_read_btn.setEnabled(True)
|
|
else:
|
|
QMessageBox.warning(self, "Ошибка", "Не удалось подключиться к порту")
|
|
except Exception as e:
|
|
QMessageBox.warning(self, "Ошибка", f"Ошибка подключения: {e}")
|
|
|
|
def closeEvent(self, event):
|
|
self.serial_tab.stop_macro()
|
|
self.raw_protocol.cancel_async()
|
|
self.raw_protocol.disconnect()
|
|
super().closeEvent(event)
|
|
|
|
def show_protocol_info(self):
|
|
"""Показать информацию о протоколе"""
|
|
info = """
|
|
ИНФОРМАЦИЯ О ПРОТОКОЛЕ:
|
|
|
|
На основе кода контроллера:
|
|
|
|
1. ФОРМАТ СООБЩЕНИЙ:
|
|
[адрес][команда][данные][CRC16-IBM]
|
|
|
|
2. КЛЮЧЕВЫЕ АДРЕСА:
|
|
- 0x200A: Регистр данных шины (запись)
|
|
- 0x200B: Регистр управления шиной
|
|
- 0x200F: Регистр данных шины (чтение)
|
|
|
|
3. ПРОТОКОЛ ШИНЫ:
|
|
ЗАПИСЬ:
|
|
1. POKE 0x200A <данные>
|
|
2. POKE 0x200B 0x80A0 | (адрес << 4)
|
|
|
|
ЧТЕНИЕ:
|
|
1. POKE 0x200B 0x00A0 | (адрес << 4)
|
|
2. PEEK 0x200F
|
|
|
|
4. ЧТО НУЖНО УТОЧНИТЬ:
|
|
- Точные коды команд CMD_RS232_PEEK и CMD_RS232_POKE
|
|
- Длину полей в сообщениях
|
|
- Формат ответов от контроллера
|
|
"""
|
|
|
|
QMessageBox.information(self, "Информация о протоколе", info)
|
|
|
|
|
|
def main():
|
|
app = QApplication(sys.argv)
|
|
|
|
# Установка стиля
|
|
app.setStyle("Fusion")
|
|
|
|
window = MainWindow()
|
|
window.show()
|
|
|
|
sys.exit(app.exec())
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|