#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
RTD1861B 波特率自动扫描工具
在上电瞬间用多个波特率监听，自动识别正确的波特率
"""

import sys
import os
import termios
import fcntl
import select
import time

PORT = '/dev/cu.usbmodem21302'

# 要扫描的波特率（按可能性排序）
BAUD_RATES = [115200, 921600, 57600, 38400, 230400, 19200, 9600]

# BootROM 特征字符串
KEYWORDS = [b'Realtek>', b'd/g/r>', b'Recovery', b'hwsetting', b'certificate',
            b'Linux version', b'Starting kernel', b'BootROM', b'U-Boot']


def open_serial(port, baudrate):
    fd = os.open(port, os.O_RDWR | os.O_NOCTTY)
    old_attr = termios.tcgetattr(fd)
    new_attr = termios.tcgetattr(fd)
    new_attr[0] = 0
    new_attr[1] = 0
    new_attr[2] = termios.CS8 | termios.CREAD | termios.CLOCAL
    new_attr[3] = 0
    new_attr[6][termios.VMIN] = 0
    new_attr[6][termios.VTIME] = 1

    # 动态获取波特率常量
    attr_name = f'B{baudrate}'
    if not hasattr(termios, attr_name):
        os.close(fd)
        return None, None
    baud_const = getattr(termios, attr_name)
    new_attr[4] = baud_const
    new_attr[5] = baud_const
    termios.tcsetattr(fd, termios.TCSANOW, new_attr)

    fl = fcntl.fcntl(fd, fcntl.F_GETFL)
    fcntl.fcntl(fd, fcntl.F_SETFL, fl & ~os.O_NONBLOCK)
    return fd, old_attr


def close_serial(fd, old_attr):
    if fd is not None:
        termios.tcsetattr(fd, termios.TCSADRAIN, old_attr)
        os.close(fd)


def read_all(fd, timeout_sec):
    """在指定时间内读取所有数据"""
    data = b''
    start = time.time()
    while time.time() - start < timeout_sec:
        ready, _, _ = select.select([fd], [], [], 0.05)
        if ready:
            try:
                chunk = os.read(fd, 4096)
                if chunk:
                    data += chunk
            except OSError:
                break
        elif data:
            break
    return data


def try_baudrate(port, baudrate, listen_sec=4):
    """尝试一个波特率，监听一段时间"""
    fd, old_attr = open_serial(port, baudrate)
    if fd is None:
        return None

    try:
        # 清空缓冲区
        read_all(fd, 0.3)

        # 发送 Esc 键（BootROM 进入交互模式的常用按键）
        os.write(fd, b'\x1b')
        time.sleep(0.1)

        # 持续监听
        data = read_all(fd, listen_sec)
        return data
    finally:
        close_serial(fd, old_attr)


def detect_baudrate():
    print("=" * 60)
    print("  RTD1861B 波特率自动扫描工具")
    print("=" * 60)
    print(f"目标串口: {PORT}")
    print(f"扫描波特率: {BAUD_RATES}")
    print()
    print("【操作步骤】")
    print("1. 确保车机已彻底断电")
    print("2. 按回车键开始扫描")
    print("3. 按回车后，立即给车机上电")
    print("=" * 60)

    input("\n确认车机已断电？按回车开始扫描...")

    print("\n[*] 扫描中，请立即给车机上电...")
    print("-" * 60)

    results = []
    for baud in BAUD_RATES:
        print(f"\n  [尝试] {baud} bps...", end='', flush=True)
        data = try_baudrate(PORT, baud, listen_sec=2.5)

        if data:
            text = data.decode('utf-8', errors='replace').replace('\n', ' ').replace('\r', ' ')
            text = ' '.join(text.split())[:80]
            print(f" 收到 {len(data)} 字节 -> {text}")

            # 检查是否包含特征字符串
            lower = data.lower()
            matched = [k.decode() for k in KEYWORDS if k.lower() in lower]
            if matched:
                print(f"  ✅ 匹配到特征: {matched}")
                results.append((baud, data, matched))
        else:
            print(" 无数据")

    print("\n" + "=" * 60)
    print("【扫描结果】")

    if results:
        # 按数据量排序，数据最多的最可能是正确波特率
        results.sort(key=lambda x: len(x[1]), reverse=True)
        best_baud, best_data, best_match = results[0]

        print(f"\n  🎯 最可能的波特率: {best_baud}")
        print(f"     收到数据: {len(best_data)} 字节")
        print(f"     匹配特征: {best_match}")
        print(f"\n  其他有数据的波特率:")
        for baud, data, match in results[1:]:
            print(f"     {baud} bps -> {len(data)} 字节, 特征: {match}")

        print(f"\n  【建议】使用波特率 {best_baud} 运行 check_uart0.py")
    else:
        print("\n  ❌ 所有波特率均未收到数据")
        print("     可能原因:")
        print("     - 上电太晚，错过了 BootROM 输出窗口")
        print("     - 当前连接的不是 UART0（可能是调试串口）")
        print("     - 波特率不在扫描列表中")
        print("\n  【建议】重新断电，按回车后立即上电。")

    print("=" * 60)


if __name__ == '__main__':
    try:
        detect_baudrate()
    except KeyboardInterrupt:
        print("\n\n[!] 用户取消")
        sys.exit(0)
