"""Три автономных примера общей консоли templates без подключения к аппаратуре.""" # Примеры показывают служебный текст, CAN и двоичный RS485 на одном компоненте. import argparse # Ключ --kind выбирает один пример для отдельного запуска. import time # Время в модели кадра соответствует обычному источнику пакетов приложения. from set_devices.can485_board import BoardFrame # Штатная модель строит RS485-пакет с настоящим CRC. from set_devices.can_monitor import decode_protocol # CAN расшифровывается действующим декодером templates. from set_devices.can_transport import build_frame # Транспортный кадр не собирается вручную в UI. from set_devices.qt_ports.console import ConsoleView # Все примеры используют ту же консоль, что SETGUI. try: # Выбираем доступную версию Qt без зависимости от приложения SETGUI. from PySide6.QtWidgets import QApplication, QTabWidget # Вкладки позволяют сравнить три независимых журнала. except ImportError: # Сохраняем совместимость примера с портом Qt 5. from PySide2.QtWidgets import QApplication, QTabWidget # Интерфейс запуска одинаков для обеих версий Qt. def create_examples(): # Фабрика доступна также тесту и генератору снимков интерфейса. service = ConsoleView(limit=4000) # Первый журнал показывает служебные ответы и команды платы. service.append_message(">>> V", direction="TX", color="#8fd18f") # Метка отправки демонстрирует независимый фильтр TX. service.append_message("#OK driver started", direction="RX", color="#6fa8dc") # Ответ устройства показывает цвет и фильтр RX. service.append_message("#ERR transmit failed (no ack / bus busy)", color="#ff7b7b") # Ошибка остаётся видна независимо от фильтров направления. can = ConsoleView(limit=4000, payloads=True) # Второй пример добавляет переключение представления настоящих байтов CAN. frame = build_frame(0x701, b"\x05", ide=False, rtr=False) # ID 0x701 и байт 05 задают heartbeat CANopen узла 1 в Operational. decoded = decode_protocol(frame, "deif") # Подпись события берётся из штатного протокольного декодера. can.append_message("RX CAN 0x701 · " + decoded.summary, direction="RX", payload=b"\x05") # Исходный payload позволяет сравнить режимы HEX и ASCII. rs485 = ConsoleView(limit=4000, payloads=True) # Третий пример показывает транспортный пакет платы отдельно от прикладного CAN. packet = BoardFrame(time.time(), False, 0x701, False, 1, b"\x05", "RS485").rs485_packet() # Пакет AA55 и CRC8 формируются кодеком templates. rs485.append_message("RX RS485 · пакет CAN485", direction="RX", payload=packet) # Консоль отображает байты, не повторяя алгоритм разбора пакета. for console in (can, rs485): # Двоичные примеры сразу демонстрируют одновременно байты и печатное представление. console.display.setCurrentText("HEX + ASCII") # Пользователь может вернуться к исходной подписи или выбрать один формат. return (("Служебная консоль", service), ("CAN", can), ("RS485", rs485)) # Каждый журнал владеет своей историей и настройками просмотра. def main(): # Точка входа запускается обычным Python с установленным Qt-портом templates. parser = argparse.ArgumentParser(description=__doc__) # Справка объясняет назначение примеров без отдельного приложения. parser.add_argument("--kind", choices=("all", "service", "can", "rs485"), default="all") # Один пример каждого источника доступен отдельной командой. args = parser.parse_args() # Пользователь выбирает источник до создания окна. app = QApplication.instance() or QApplication([]) # Одно приложение Qt обслуживает все примеры. window = QTabWidget() # Общий просмотр не связывает состояния независимых консолей. for key, (title, console) in zip(("service", "can", "rs485"), create_examples()): # Стабильные ключи соответствуют значениям --kind. if args.kind in ("all", key): window.addTab(console.panel, title) # Выбранные примеры добавляются с общей панелью инструментов. window.setWindowTitle("Примеры консоли templates") # Заголовок явно отличает демонстрацию от подключения к плате. window.resize(1100, 480) # Начальный размер в логических пикселях позволяет видеть все инструменты. window.show() # Окно появляется только при прямом запуске примера. return app.exec() # Цикл Qt обрабатывает поиск, паузу, экспорт и изменение масштаба. if __name__ == "__main__": # Импорт фабрики в тестах не должен открывать окно или запускать цикл событий. raise SystemExit(main()) # Код завершения Qt возвращается вызывающему процессу.