#!/usr/bin/env python3
"""
UPS Modbus RTU 报文组装脚本
根据控制意图，组装完整的 Modbus RTU 报文（含 CRC16），输出二次确认拦截字符串。
"""
import argparse
import json
import sys


def crc16(data: bytes) -> int:
    """计算 Modbus CRC16（低字节在前，高字节在后）"""
    crc = 0xFFFF
    for byte in data:
        crc ^= byte
        for _ in range(8):
            if crc & 0x0001:
                crc = (crc >> 1) ^ 0xA001
            else:
                crc >>= 1
    return crc


def build_rtu_frame(slave_id: int, func: int, addr: int, val: int) -> str:
    """
    组装 Modbus RTU 完整报文（含 CRC16）
    格式：站号 功能码 地址高 地址低 值高 值低 CRC低 CRC高
    """
    frame = bytes([
        slave_id,
        func,
        (addr >> 8) & 0xFF,
        addr & 0xFF,
        (val >> 8) & 0xFF,
        val & 0xFF,
    ])
    crc = crc16(frame)
    crc_lo = crc & 0xFF
    crc_hi = (crc >> 8) & 0xFF
    full_frame = frame + bytes([crc_lo, crc_hi])
    return ' '.join(f'{b:02X}' for b in full_frame)


# 命令映射表：自然语言意图 → (功能码, 寄存器地址, 写入值, 操作说明)
COMMAND_MAP = {
    "开机":       (0x05, 5900, 0xFF00, "开机"),
    "停机":       (0x05, 5900, 0x0000, "停机"),
    "关机":       (0x05, 5900, 0x0000, "停机"),
    "紧急停机":   (0x05, 5900, 0x0000, "停机"),
    "立刻停机":   (0x05, 5900, 0x0000, "停机"),
    "立即停机":   (0x05, 5900, 0x0000, "停机"),
    "合闸":       (0x05, 5900, 0xFF00, "合闸"),
    "分闸":       (0x05, 5900, 0x0000, "分闸"),
    "远程合闸":   (0x05, 5900, 0xFF00, "合闸"),
    "远程分闸":   (0x05, 5900, 0x0000, "分闸"),
    "强制均充":   (0x05, 5901, 0xFF00, "强制均充"),
    "开启ECO模式": (0x05, 5902, 0xFF00, "开启ECO模式"),
    "关闭ECO模式": (0x05, 5902, 0x0000, "关闭ECO模式"),
    "开启蜂鸣器": (0x06, 5402, 0x0001, "开启蜂鸣器"),
    "静音蜂鸣器": (0x06, 5402, 0x0002, "静音蜂鸣器"),
    "标准电池测试": (0x06, 5403, 0x0001, "标准电池测试"),
    "深度电池测试": (0x06, 5403, 0x0002, "深度电池测试"),
    "取消电池测试": (0x06, 5403, 0x0003, "取消电池测试"),
    "设置CC充电模式": (0x06, 5404, 0x0000, "设置CC充电模式"),
    "设置CP充电模式": (0x06, 5404, 0x0001, "设置CP充电模式"),
}


def main():
    parser = argparse.ArgumentParser(description="组装 Modbus RTU 报文，输出二次确认字符串")
    parser.add_argument("--device_id", required=True, help="设备ID或名称")
    parser.add_argument("--intent", required=True, help="控制意图，如：停机、开机、强制均充")
    parser.add_argument("--slave_id", type=int, default=1, help="Modbus 从站地址（默认 1）")
    args = parser.parse_args()

    if args.intent not in COMMAND_MAP:
        print(json.dumps({
            "status": "error",
            "message": f"不支持的控制意图: {args.intent}，支持的命令: {list(COMMAND_MAP.keys())}"
        }, ensure_ascii=False))
        sys.exit(1)

    func, addr, val, label = COMMAND_MAP[args.intent]
    rtu_frame = build_rtu_frame(args.slave_id, func, addr, val)

    # 输出二次确认拦截字符串
    confirm_str = f"&**&device_id={args.device_id}|command={rtu_frame}|label={label}&**&"
    print(confirm_str)


if __name__ == "__main__":
    main()
