#!/usr/bin/env python3 import tkinter as tk from tkinter import messagebox, ttk import subprocess import sys import os import re import glob from datetime import datetime class MainApp: def __init__(self, root): self.root = root self.root.title("Мое Приложение") self.root.geometry("900x900") self.root.configure(bg='#f0f0f0') # Позиционируем окно по левому краю экрана self.position_window_left() # Увеличим шрифты для лучшей видимости на 7-дюймовом мониторе self.big_font = ('Arial', 24) self.medium_font = ('Arial', 20) self.small_font = ('Arial', 16) self.create_widgets() def position_window_left(self): """Позиционирует окно по левому краю экрана""" # Получаем размеры экрана screen_width = self.root.winfo_screenwidth() screen_height = self.root.winfo_screenheight() # Получаем размеры окна window_width = 900 window_height = 900 # Вычисляем позицию для левого края x_position = 0 y_position = (screen_height - window_height) // 2 # Устанавливаем позицию окна self.root.geometry(f"{window_width}x{window_height}+{x_position}+{y_position}") def create_widgets(self): # Заголовок title_label = tk.Label( self.root, text="Главное меню", font=('Arial', 24, 'bold'), bg='#f0f0f0', fg='#333333' ) title_label.pack(pady=20) # Кнопка Авто STM32 self.auto_stm32_btn = tk.Button( self.root, text="Тестовое ПО", font=self.big_font, bg='#4CAF50', fg='white', width=15, height=2, command=lambda: self.auto_mode('test') ) self.auto_stm32_btn.pack(pady=10) # Кнопка Авто ESP32 self.auto_esp32_btn = tk.Button( self.root, text="Рабочее ПО", font=self.big_font, bg='#2196F3', fg='white', width=15, height=2, command=lambda: self.auto_mode('work') ) self.auto_esp32_btn.pack(pady=10) # Кнопка Minicom self.minicom_btn = tk.Button( self.root, text="Minicom", font=self.big_font, bg='#FF9800', fg='white', width=15, height=2, command=self.open_minicom ) self.minicom_btn.pack(pady=10) # Кнопка Выход self.exit_btn = tk.Button( self.root, text="Выход", font=self.big_font, bg='#f44336', fg='white', width=15, height=2, command=self.exit_app ) self.exit_btn.pack(pady=10) # Область для лога log_frame = tk.Frame(self.root, bg='#f0f0f0') log_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=10) tk.Label( log_frame, text="Лог выполнения:", font=self.medium_font, bg='#f0f0f0', fg='#333333' ).pack(anchor=tk.W) # Текстовое поле для лога с прокруткой log_container = tk.Frame(log_frame) log_container.pack(fill=tk.BOTH, expand=True, pady=5) self.log_text = tk.Text( log_container, height=12, font=self.small_font, bg='#2c3e50', fg='#ecf0f1', insertbackground='white', wrap=tk.WORD ) scrollbar = tk.Scrollbar(log_container, orient=tk.VERTICAL, command=self.log_text.yview) self.log_text.configure(yscrollcommand=scrollbar.set) self.log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # Статус бар self.status_var = tk.StringVar() self.status_var.set("Готов к работе") status_bar = tk.Label( self.root, textvariable=self.status_var, font=self.medium_font, bg='#dddddd', relief=tk.SUNKEN, anchor=tk.W ) status_bar.pack(side=tk.BOTTOM, fill=tk.X) # Добавляем начальное сообщение в лог self.add_to_log("✅ Приложение запущено и готово к работе") self.add_to_log("📐 Окно позиционировано по левому краю (900x900)") def open_minicom(self): """Открывает minicom в отдельном терминале""" try: self.status_var.set("Запуск minicom...") self.add_to_log("🔄 Запускаю minicom...") # Автоматически находим порт ports = glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') if ports: port = "/dev/ttyUSB1" self.add_to_log(f"🔌 Найден порт: {port}") subprocess.Popen([ 'lxterminal', '--geometry=80x60', '-e', f'bash -c "minicom -D {port} -b 115200; exec bash"' ]) self.status_var.set("Minicom запущен") self.add_to_log(f"✅ Minicom запущен на {port}") else: self.add_to_log("❌ COM-порты не найдены") except Exception as e: self.status_var.set("Ошибка запуска minicom") self.add_to_log(f"❌ Ошибка запуска minicom: {str(e)}") def add_to_log(self, message): """Добавляет сообщение в лог с временной меткой""" timestamp = datetime.now().strftime("%H:%M:%S") formatted_message = f"[{timestamp}] {message}\n" self.log_text.insert(tk.END, formatted_message) self.log_text.see(tk.END) self.root.update_idletasks() def find_serial_ports(self): """Поиск доступных COM-портов""" ports = [] # Поиск на Linux if sys.platform.startswith('linux'): ports = glob.glob('/dev/ttyUSB*') + glob.glob('/dev/ttyACM*') # Поиск на Windows elif sys.platform.startswith('win'): ports = [f"COM{i}" for i in range(1, 256)] # Поиск на MacOS elif sys.platform.startswith('darwin'): ports = glob.glob('/dev/tty.*') available_ports = [] for port in ports: if sys.platform.startswith('win'): # На Windows просто проверяем существование if os.path.exists(port): available_ports.append(port) else: # На Linux/Mac проверяем доступность try: if os.path.exists(port) and os.access(port, os.R_OK): available_ports.append(port) except: pass return available_ports def check_stm32_connection(self): """Проверка подключения STM32""" try: result = subprocess.run(['st-info', '--chipid'], capture_output=True, text=True, timeout=10) chip_id = None # Ищем hex число в выводе match = re.search(r'0x[0-9A-Fa-f]+', result.stdout + result.stderr) if match: chip_id = match.group(0) if chip_id and chip_id != "0x0000": return True, chip_id else: return False, None except Exception as e: return False, None def check_esp32_connection(self): """Проверка подключения ESP32""" try: # Ищем порт ESP32 ports = self.find_serial_ports() if not ports: return False, None, None port = "/dev/ttyUSB0" # Берем первый доступный порт # Пробуем получить информацию о чипе ESP32 result = subprocess.run([ 'esptool.py', '--port', port, 'chip_id' ], capture_output=True, text=True, timeout=10) if result.returncode == 0: return True, port, "ESP32 обнаружен" else: return False, port, None except Exception as e: return False, None, str(e) def auto_mode(self, mcu_type): """Автоматический режим для STM32 или ESP32""" self.status_var.set(f"Режим Авто {mcu_type.upper()} активирован") self.add_to_log(f"🔄 Запуск автоматического режима для {mcu_type.upper()}...") import time if mcu_type == 'test': self.auto_mode_erase_stm32() time.sleep(3) self.auto_mode_test_esp32() time.sleep(3) self.auto_mode_test_stm32() elif mcu_type == 'work': self.auto_mode_work() def auto_mode_erase_stm32(self): """Тестовое ПО""" flash_success = False try: # Проверка подключения микроконтроллера self.add_to_log("🔍 Проверка подключения STM32...") connected, chip_id = self.check_stm32_connection() if connected: self.status_var.set(f"✅ STM32 подключен, Chip ID: {chip_id}") self.add_to_log(f"✅ STM32 подключен, Chip ID: {chip_id}") # Проверка файла прошивки self.add_to_log("🔍 Очистка памяти STM32...") flash_result = subprocess.run([ 'st-flash', 'erase' ], capture_output=True, text=True, timeout=60) if flash_result.returncode == 0: self.status_var.set("✅ Очистка STM32 завершена успешно!") self.add_to_log("✅ Очистка STM32 завершена успешно!") flash_success = True else: self.status_var.set("❌ Ошибка очистки STM32") self.add_to_log(f"❌ Ошибка очистки STM32: {flash_result.stderr}") else: self.status_var.set("❌ STM32 не подключен") self.add_to_log("❌ STM32 не подключен") except subprocess.TimeoutExpired: self.status_var.set("❌ Таймаут операции STM32") self.add_to_log("❌ Таймаут операции STM32!") except Exception as e: self.status_var.set("❌ Ошибка выполнения STM32") self.add_to_log(f"❌ Произошла ошибка STM32: {str(e)}") self.add_to_log("🔚 Очистка STM32 завершена") def auto_mode_test_stm32(self): """Тестовое ПО""" flash_success = False try: # Проверка подключения микроконтроллера self.add_to_log("🔍 Проверка подключения STM32...") connected, chip_id = self.check_stm32_connection() if connected: self.status_var.set(f"✅ STM32 подключен, Chip ID: {chip_id}") self.add_to_log(f"✅ STM32 подключен, Chip ID: {chip_id}") # Проверка файла прошивки self.add_to_log("🔍 Поиск файла прошивки STM32...") firmware_path = os.path.expanduser("~/fw/TestStand_FW_STM32.bin") if os.path.exists(firmware_path): file_size = os.path.getsize(firmware_path) self.status_var.set("✅ Файл прошивки STM32 найден") self.add_to_log(f"✅ Файл прошивки найден: TestStand_FW_STM32.bin ({file_size} байт)") # Прошивка микроконтроллера self.status_var.set("🔄 Идет прошивка STM32...") self.add_to_log("🔄 Начинаю прошивку STM32...") flash_result = subprocess.run([ 'st-flash', '--reset', 'write', firmware_path, '0x08000000' ], capture_output=True, text=True, timeout=60) if flash_result.returncode == 0: self.status_var.set("✅ Прошивка STM32 завершена успешно!") self.add_to_log("✅ Прошивка STM32 завершена успешно!") flash_success = True else: self.status_var.set("❌ Ошибка прошивки STM32") self.add_to_log(f"❌ Ошибка прошивки STM32: {flash_result.stderr}") else: self.status_var.set("❌ Файл прошивки STM32 не найден") self.add_to_log("❌ Файл прошивки STM32 не найден") self.show_available_files() else: self.status_var.set("❌ STM32 не подключен") self.add_to_log("❌ STM32 не подключен") except subprocess.TimeoutExpired: self.status_var.set("❌ Таймаут операции STM32") self.add_to_log("❌ Таймаут операции STM32!") except Exception as e: self.status_var.set("❌ Ошибка выполнения STM32") self.add_to_log(f"❌ Произошла ошибка STM32: {str(e)}") self.add_to_log("🔚 Автоматический режим STM32 завершен") def auto_mode_test_esp32(self): try: # Проверка подключения микроконтроллера self.add_to_log("🔍 Проверка подключения ESP32...") connected, port, chip_info = self.check_esp32_connection() port = "/dev/ttyUSB0" if connected and port: self.status_var.set(f"✅ ESP32 подключен на {port}") self.add_to_log(f"✅ ESP32 подключен на {port}") if chip_info: self.add_to_log(f"ℹ️ {chip_info}") # Проверка файлов прошивки ESP32 self.add_to_log("🔍 Поиск файлов прошивки ESP32...") bootloader_path = os.path.expanduser("~/fw/bootloader.bin") firmware_path = os.path.expanduser("~/fw/TestStand_FW_ESP32.bin") partition_path = os.path.expanduser("~/fw/partition-table.bin") files_exist = all([ os.path.exists(bootloader_path), os.path.exists(firmware_path), os.path.exists(partition_path) ]) if files_exist: self.status_var.set("✅ Файлы прошивки ESP32 найдены") self.add_to_log("✅ Все файлы прошивки ESP32 найдены:") self.add_to_log(f" - bootloader.bin ({os.path.getsize(bootloader_path)} байт)") self.add_to_log(f" - TestStand_FW_ESP32.bin ({os.path.getsize(firmware_path)} байт)") self.add_to_log(f" - partition-table.bin ({os.path.getsize(partition_path)} байт)") # Прошивка ESP32 self.status_var.set("🔄 Идет прошивка ESP32...") self.add_to_log("🔄 Начинаю прошивку ESP32...") flash_command = [ 'esptool.py', '--chip', 'esp32', '--port', port, '--baud', '576000', 'write_flash', '--flash_mode', 'dio', '--flash_freq', '40m', '--flash_size', 'detect', '0x1000', bootloader_path, '0x10000', firmware_path, '0x8000', partition_path ] self.add_to_log(f"🔧 Команда прошивки: {' '.join(flash_command)}") flash_result = subprocess.run(flash_command, capture_output=True, text=True, timeout=120) if flash_result.returncode == 0: self.status_var.set("✅ Прошивка ESP32 завершена успешно!") self.add_to_log("✅ Прошивка ESP32 завершена успешно!") flash_success = True else: self.status_var.set("❌ Ошибка прошивки ESP32") self.add_to_log(f"❌ Ошибка прошивки ESP32: {flash_result.stderr}") else: self.status_var.set("❌ Не все файлы прошивки ESP32 найдены") self.add_to_log("❌ Не все файлы прошивки ESP32 найдены") self.show_available_files() else: self.status_var.set("❌ ESP32 не подключен") self.add_to_log("❌ ESP32 не подключен или порт не найден") except subprocess.TimeoutExpired: self.status_var.set("❌ Таймаут операции ESP32") self.add_to_log("❌ Таймаут операции ESP32!") except Exception as e: self.status_var.set("❌ Ошибка выполнения ESP32") self.add_to_log(f"❌ Произошла ошибка ESP32: {str(e)}") self.add_to_log("🔚 Автоматический режим ESP32 завершен") def auto_mode_work(self): """Рабочее ПО""" flash_success = False try: # Проверка подключения микроконтроллера self.add_to_log("🔍 Проверка подключения STM32...") connected, chip_id = self.check_stm32_connection() if connected: self.status_var.set(f"✅ STM32 подключен, Chip ID: {chip_id}") self.add_to_log(f"✅ STM32 подключен, Chip ID: {chip_id}") # Проверка файла прошивки self.add_to_log("🔍 Поиск файла прошивки STM32...") firmware_path = os.path.expanduser("~/fw/w/STM_2.08_NO_PROTECTION.bin") if os.path.exists(firmware_path): file_size = os.path.getsize(firmware_path) self.status_var.set("✅ Файл прошивки STM32 найден") self.add_to_log(f"✅ Файл прошивки найден: TestStand_FW_STM32.bin ({file_size} байт)") # Прошивка микроконтроллера self.status_var.set("🔄 Идет прошивка STM32...") self.add_to_log("🔄 Начинаю прошивку STM32...") flash_result = subprocess.run([ 'st-flash', '--reset', 'write', firmware_path, '0x08000000' ], capture_output=True, text=True, timeout=30) if flash_result.returncode == 0: self.status_var.set("✅ Прошивка STM32 завершена успешно!") self.add_to_log("✅ Прошивка STM32 завершена успешно!") flash_success = True else: self.status_var.set("❌ Ошибка прошивки STM32") self.add_to_log(f"❌ Ошибка прошивки STM32: {flash_result.stderr}") else: self.status_var.set("❌ Файл прошивки STM32 не найден") self.add_to_log("❌ Файл прошивки STM32 не найден") self.show_available_files() else: self.status_var.set("❌ STM32 не подключен") self.add_to_log("❌ STM32 не подключен") except subprocess.TimeoutExpired: self.status_var.set("❌ Таймаут операции STM32") self.add_to_log("❌ Таймаут операции STM32!") except Exception as e: self.status_var.set("❌ Ошибка выполнения STM32") self.add_to_log(f"❌ Произошла ошибка STM32: {str(e)}") self.add_to_log("🔚 Автоматический режим STM32 завершен") """Автоматический режим для ESP32""" flash_success = False try: # Проверка подключения микроконтроллера self.add_to_log("🔍 Проверка подключения ESP32...") connected, port, chip_info = self.check_esp32_connection() if connected and port: self.status_var.set(f"✅ ESP32 подключен на {port}") self.add_to_log(f"✅ ESP32 подключен на {port}") if chip_info: self.add_to_log(f"ℹ️ {chip_info}") # Проверка файлов прошивки ESP32 self.add_to_log("🔍 Поиск файлов прошивки ESP32...") bootloader_path = os.path.expanduser("~/fw/w/bootloader.bin") firmware_path = os.path.expanduser("~/fw/w/ET_22KW_1.0b.bin") partition_path = os.path.expanduser("~/fw/w/partition-table.bin") www_path = os.path.expanduser("~/fw/w/www.bin") files_exist = all([ os.path.exists(bootloader_path), os.path.exists(firmware_path), os.path.exists(partition_path), os.path.exists(www_path) ]) if files_exist: self.status_var.set("✅ Файлы прошивки ESP32 найдены") self.add_to_log("✅ Все файлы прошивки ESP32 найдены:") self.add_to_log(f" - bootloader.bin ({os.path.getsize(bootloader_path)} байт)") self.add_to_log(f" - TestStand_FW_ESP32.bin ({os.path.getsize(firmware_path)} байт)") self.add_to_log(f" - partition-table.bin ({os.path.getsize(partition_path)} байт)") self.add_to_log(f" - www.bin ({os.path.getsize(www_path)} байт)") # Прошивка ESP32 self.status_var.set("🔄 Идет прошивка ESP32...") self.add_to_log("🔄 Начинаю прошивку ESP32...") flash_command = [ 'esptool.py', '--chip', 'esp32', '--port', port, '--baud', '576000', 'write_flash', '--flash_mode', 'dio', '--flash_freq', '40m', '--flash_size', 'detect', '0x1000', bootloader_path, '0x10000', firmware_path, '0x8000', partition_path, '0x210000', www_path ] self.add_to_log(f"🔧 Команда прошивки: {' '.join(flash_command)}") flash_result = subprocess.run(flash_command, capture_output=True, text=True, timeout=120) if flash_result.returncode == 0: self.status_var.set("✅ Прошивка ESP32 завершена успешно!") self.add_to_log("✅ Прошивка ESP32 завершена успешно!") flash_success = True else: self.status_var.set("❌ Ошибка прошивки ESP32") self.add_to_log(f"❌ Ошибка прошивки ESP32: {flash_result.stderr}") else: self.status_var.set("❌ Не все файлы прошивки ESP32 найдены") self.add_to_log("❌ Не все файлы прошивки ESP32 найдены") self.show_available_files() else: self.status_var.set("❌ ESP32 не подключен") self.add_to_log("❌ ESP32 не подключен или порт не найден") except subprocess.TimeoutExpired: self.status_var.set("❌ Таймаут операции ESP32") self.add_to_log("❌ Таймаут операции ESP32!") except Exception as e: self.status_var.set("❌ Ошибка выполнения ESP32") self.add_to_log(f"❌ Произошла ошибка ESP32: {str(e)}") self.add_to_log("🔚 Автоматический режим ESP32 завершен") def show_available_files(self): """Показывает доступные файлы в папке fw""" fw_dir = os.path.expanduser("~/fw") if os.path.exists(fw_dir): files = os.listdir(fw_dir) bin_files = [f for f in files if f.endswith('.bin')] if bin_files: self.add_to_log("📁 Доступные файлы в папке fw:") for file in bin_files: self.add_to_log(f" - {file}") else: self.add_to_log("📁 В папке fw нет .bin файлов") else: self.add_to_log("📁 Папка fw не существует") def exit_app(self): if messagebox.askyesno("Выход", "Вы уверены, что хотите выйти?"): self.status_var.set("Завершение работы...") self.add_to_log("🔴 Приложение завершает работу...") self.root.quit() sys.exit() def main(): try: root = tk.Tk() app = MainApp(root) root.mainloop() except KeyboardInterrupt: print("\nПриложение завершено") except Exception as e: print(f"Ошибка: {e}") messagebox.showerror("Ошибка", f"Произошла ошибка: {e}") if __name__ == "__main__": main()