from __future__ import annotations import os from dataclasses import dataclass from enum import Enum from pathlib import Path from typing import Tuple class _StrEnumMixin(str, Enum): """Behaves like StrEnum on Python < 3.11.""" class Direction(_StrEnumMixin): RX = "rx" TX = "tx" INFO = "info" class Mode(_StrEnumMixin): NORMAL = "normal" DOWNLOAD = "download" RESET = "reset" CHECKBOX_STYLE = ( "QCheckBox::indicator {" " width: 14px; height: 14px; border: 1px solid #666; border-radius: 2px; background: #ffffff;" "}" "QCheckBox::indicator:checked {" " background: #1b5e20; border: 1px solid #1b5e20;" "}" ) APP_NAME = "Ameba Control Panel" APP_VERSION = "3.1.0" UI_LOG_TAIL_LINES = 100_000 LOG_FLUSH_INTERVAL_MS = 30 LOG_ARCHIVE_MAX = 500_000 LOG_FLUSH_BATCH_LIMIT = 200 PARTIAL_LINE_HOLD_SEC = 0.3 PERF_UPDATE_INTERVAL_MS = 1_000 PORT_REFRESH_INTERVAL_MS = 5_000 DEFAULT_BAUD = 1_500_000 COMMON_BAUD_RATES = [ 115_200, 230_400, 460_800, 921_600, 1_000_000, DEFAULT_BAUD, 2_000_000, 3_000_000, ] TIMESTAMP_FMT = "%Y-%m-%d %H:%M:%S.%f" @dataclass class DeviceProfile: key: str label: str rx_color: str = "#1a8a3d" tx_color: str = "#2944a8" info_color: str = "#7970a9" DEFAULT_PROFILE = DeviceProfile("dut_1", "DUT 1") def parse_baud(text: str) -> int: try: return int(text) except (ValueError, TypeError): return DEFAULT_BAUD def app_data_dir() -> Path: base = os.environ.get("LOCALAPPDATA") if base: return Path(base) / "AmebaControlPanel" # Fallback for non-Windows dev environments. return Path.home() / ".local" / "share" / "AmebaControlPanel"