Files
app_rf915_dump/test_protocol.py
2026-04-15 07:53:51 +08:00

228 lines
8.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试 MT6 RFID 读卡器协议函数
"""
import sys
import os
# 添加 PySimpleGUI 目录到路径
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), 'PySimpleGUI'))
# 导入协议函数
from rfid_tester import (
calc_outer_checksum,
build_setreq_frame,
parse_getres_frame,
cmd_get_version,
cmd_buzzer,
cmd_set_power,
cmd_set_mode,
cmd_read_epc,
cmd_select_card,
cmd_write_epc,
)
def test_calc_outer_checksum():
"""测试校验和计算"""
print("\n=== 测试校验和计算 ===")
# 根据文档,读版本号命令的校验和应该是 0xc1
# Data Length: 01 00 (小端序)
# Data: c0
data_len = bytes([0x01, 0x00])
data = bytes([0xc0])
checksum = calc_outer_checksum(data_len, data)
print(f"读版本号校验和: 0x{checksum:02x} (期望: 0xc1)")
assert checksum == 0xc1, f"校验和计算错误: 期望 0xc1, 实际 0x{checksum:02x}"
# 打开蜂鸣器的校验和应该是 0xce
# Data Length: 02 00
# Data: cd 01
data_len = bytes([0x02, 0x00])
data = bytes([0xcd, 0x01])
checksum = calc_outer_checksum(data_len, data)
print(f"打开蜂鸣器校验和: 0x{checksum:02x} (期望: 0xce)")
assert checksum == 0xce, f"校验和计算错误: 期望 0xce, 实际 0x{checksum:02x}"
# 设置功率=8的校验和应该是 0xc6
# Data Length: 02 00
# Data: cc 08
data_len = bytes([0x02, 0x00])
data = bytes([0xcc, 0x08])
checksum = calc_outer_checksum(data_len, data)
print(f"设置功率=8校验和: 0x{checksum:02x} (期望: 0xc6)")
assert checksum == 0xc6, f"校验和计算错误: 期望 0xc6, 实际 0x{checksum:02x}"
print("校验和测试通过!")
def test_build_setreq_frame():
"""测试帧构建"""
print("\n=== 测试帧构建 ===")
# 测试读版本号命令
cmd = cmd_get_version()
frame = build_setreq_frame(cmd)
# 根据文档,应该是: 01 00 00 00 00 06 00 00 02 01 00 c0 c1 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x02, 0x01, 0x00, 0xc0, 0xc1, 0x03])
print(f"读版本号帧 (前14字节): {frame[:14].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:14] == expected, f"读版本号帧不匹配"
assert len(frame) == 256, f"帧长度应为256字节实际为{len(frame)}"
print("读版本号帧测试通过!")
# 测试打开蜂鸣器命令
cmd = cmd_buzzer(True)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cd 01 ce 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcd, 0x01, 0xce, 0x03])
print(f"打开蜂鸣器帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"打开蜂鸣器帧不匹配"
print("打开蜂鸣器帧测试通过!")
# 测试关闭蜂鸣器命令
cmd = cmd_buzzer(False)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cd 00 cf 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcd, 0x00, 0xcf, 0x03])
print(f"关闭蜂鸣器帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"关闭蜂鸣器帧不匹配"
print("关闭蜂鸣器帧测试通过!")
# 测试设置功率命令
cmd = cmd_set_power(8)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 cc 08 c6 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0xcc, 0x08, 0xc6, 0x03])
print(f"设置功率=8帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"设置功率帧不匹配"
print("设置功率帧测试通过!")
# 测试设置被动模式命令
cmd = cmd_set_mode(2)
frame = build_setreq_frame(cmd)
# 根据文档: 01 00 00 00 00 07 00 00 02 02 00 0f 02 0f 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x02, 0x02, 0x00, 0x0f, 0x02, 0x0f, 0x03])
print(f"设置被动模式帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"设置模式帧不匹配"
print("设置模式帧测试通过!")
# 测试读取 EPC 命令
cmd = cmd_read_epc()
frame = build_setreq_frame(cmd)
print(f"读取EPC帧 (前20字节): {frame[:20].hex()}")
# 验证帧结构
assert frame[0] == 0x01, "Report ID 应为 0x01"
assert frame[1:5] == b'\x00\x00\x00\x00', "固定字段应为 0x00000000"
assert frame[7:9] == b'\x00\x02', "Constant 应为 0x0002"
print("读取EPC帧测试通过!")
def test_parse_getres_frame():
"""测试响应帧解析"""
print("\n=== 测试响应帧解析 ===")
# 模拟读版本号成功的响应
# Report ID: 0x03
# 响应数据: 00 + 版本字符串 "MT6_RF915_RW"
version_str = b"MT6_RF915_RW"
response = bytearray()
response.append(0x03) # Report ID
response.extend([0x00, 0x00, 0x00, 0x00]) # Fixed
frame_len = 2 + 2 + 1 + len(version_str) # constant + data_len + status + version
response.extend(frame_len.to_bytes(2, 'little')) # Frame Length
response.extend([0x00, 0x02]) # Constant
data_len = 1 + len(version_str)
response.extend(data_len.to_bytes(2, 'little')) # Data Length
response.append(0x00) # Status = 成功
response.extend(version_str) # Version string
# 计算校验和
checksum = calc_outer_checksum(data_len.to_bytes(2, 'little'), bytes([0x00]) + version_str)
response.append(checksum)
response.append(0x03) # End Marker
result = parse_getres_frame(bytes(response))
assert result is not None, "解析失败"
status, data = result
print(f"状态: 0x{status:02x} (期望: 0x00)")
print(f"数据: {data}")
assert status == 0x00, f"状态应为 0x00实际为 0x{status:02x}"
assert data.decode('ascii').startswith("MT6"), "版本字符串应包含 MT6"
print("响应帧解析测试通过!")
def test_command_functions():
"""测试命令生成函数"""
print("\n=== 测试命令生成函数 ===")
# 测试读版本号命令
cmd = cmd_get_version()
print(f"读版本号命令: {cmd.hex()}")
assert cmd == bytes([0xc0]), f"读版本号命令应为 c0"
# 测试蜂鸣器命令
cmd = cmd_buzzer(True)
print(f"打开蜂鸣器命令: {cmd.hex()}")
assert cmd == bytes([0xcd, 0x01]), f"打开蜂鸣器命令应为 cd 01"
cmd = cmd_buzzer(False)
print(f"关闭蜂鸣器命令: {cmd.hex()}")
assert cmd == bytes([0xcd, 0x00]), f"关闭蜂鸣器命令应为 cd 00"
# 测试设置功率命令
cmd = cmd_set_power(5)
print(f"设置功率=5命令: {cmd.hex()}")
assert cmd == bytes([0xcc, 0x05]), f"设置功率=5命令应为 cc 05"
# 测试设置模式命令
cmd = cmd_set_mode(1)
print(f"设置单标签巡查模式命令: {cmd.hex()}")
assert cmd == bytes([0x0f, 0x01]), f"设置单标签巡查模式命令应为 0f 01"
cmd = cmd_set_mode(2)
print(f"设置被动模式命令: {cmd.hex()}")
assert cmd == bytes([0x0f, 0x02]), f"设置被动模式命令应为 0f 02"
# 测试读取 EPC 命令
cmd = cmd_read_epc()
print(f"读取EPC命令: {cmd.hex()}")
assert cmd == bytes([0xce, 0xbb, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7e]), f"读取EPC命令不匹配"
print("命令生成函数测试通过!")
def main():
"""主测试函数"""
print("=" * 60)
print("MT6 RFID 读卡器协议函数测试")
print("=" * 60)
try:
test_calc_outer_checksum()
test_build_setreq_frame()
test_parse_getres_frame()
test_command_functions()
print("\n" + "=" * 60)
print("所有测试通过!")
print("=" * 60)
return 0
except AssertionError as e:
print(f"\n测试失败: {e}")
return 1
except Exception as e:
print(f"\n测试出错: {e}")
import traceback
traceback.print_exc()
return 1
if __name__ == '__main__':
sys.exit(main())