#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
本地时间同步服务（PC -> MCU 板子）

功能：
    周期性把本机（PC）的本地时间，通过 TCP 推送到 STM32 板子。
    板子端在 timeSyncTask 中以 TCP Server 方式监听端口，收到后调用
    sys_clock_set_unix() 更新系统墙钟并写回 SD2506 RTC，使板子时间 == 你电脑的时间。

协议（板子端实现见 App/time_sync.c 的 time_sync_handle_conn）：
    字节 0..3 : 魔术字 "TIME" (0x54 0x49 0x4D 0x45)
    字节 4..7 : 本地 Unix 时间戳，uint32，大端（主机字节序转换后由板子分解）

用法：
    python time_sync_server.py                 # 默认推送到 192.168.1.100:8888
    python time_sync_server.py 192.168.1.100   # 指定板子 IP
    python time_sync_server.py 192.168.1.100 9000 3   # 指定端口与间隔(秒)

按 Ctrl+C 停止。
"""

import socket
import struct
import sys
import time
import calendar

DEFAULT_MCU_IP = "192.168.1.100"
DEFAULT_PORT = 8888
DEFAULT_INTERVAL = 5.0


def main():
    mcu_ip = sys.argv[1] if len(sys.argv) > 1 else DEFAULT_MCU_IP
    port = int(sys.argv[2]) if len(sys.argv) > 2 else DEFAULT_PORT
    interval = float(sys.argv[3]) if len(sys.argv) > 3 else DEFAULT_INTERVAL

    print("[time_sync] 本地时间推送服务已启动（TCP 客户端）")
    print(f"   目标板子 : {mcu_ip}:{port}")
    print(f"   推送间隔 : {interval}s")
    print(f"   协议帧   : 'TIME' + uint32(BE) 本地 Unix 时间戳")
    print("[time_sync] 按 Ctrl+C 停止")
    print("-" * 48)

    while True:
        try:
            # 本地 wall-clock 当作 UTC 算出的 epoch（与电脑显示一致）。
            # 注意：板子 RTC 存本地时间且 unix_to_sd2506 无时区处理，
            # 故必须发"本地墙钟当 UTC"的伪 epoch（calendar.timegm），
            # 不能用 time.mktime（返回真正 UTC epoch，会导致板子慢 8 小时）。
            local_epoch = int(calendar.timegm(time.localtime()))
            pkt = b"TIME" + struct.pack(">I", local_epoch)

            with socket.create_connection((mcu_ip, port), timeout=5) as sock:
                sock.sendall(pkt)
                # 关键：发送后保持连接打开，等板子读完再关。
                # 若立即 close，CH395F 收到 FIN 会丢弃接收缓冲里尚未被板子读出的
                # 8 字节时间包，导致板子 net_recv 看到 CLOSED 而无数据、时间同步失败。
                # 这里 recv 直到板子主动关闭（EOF）或 2s 超时，确保板子先读到数据。
                sock.settimeout(2.0)
                try:
                    sock.recv(64)
                except (socket.timeout, OSError):
                    pass

            now_str = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
            print(f"[{time.strftime('%H:%M:%S')}] -> {now_str}  (epoch={local_epoch})")
        except OSError as e:
            print(f"[{time.strftime('%H:%M:%S')}] 连接/发送失败: {e}")

        time.sleep(interval)


if __name__ == "__main__":
    try:
        main()
    except KeyboardInterrupt:
        print("\n[time_sync] 已停止")
