Files
app_rf915_dump/test_protocol.py
2026-04-15 09:30:07 +08:00

308 lines
12 KiB
Python
Raw Permalink 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_factory_reset,
cmd_read_format,
cmd_set_format,
cmd_buzzer,
cmd_rf_power,
cmd_set_power,
cmd_set_mode,
cmd_read_epc,
cmd_select_card,
cmd_write_epc,
)
def test_calc_outer_checksum():
"""测试校验和计算"""
print("\n=== 测试校验和计算 ===")
# 根据文档,读版本号命令
# Data Length: 00 01 (大端序)
# Data: c0
data_len = bytes([0x00, 0x01])
data = bytes([0xc0])
checksum = calc_outer_checksum(data_len, data)
print(f"读版本号校验和: 0x{checksum:02x} (期望: 0xc1)")
assert checksum == 0xc1, f"校验和计算错误: 期望 0xc1, 实际 0x{checksum:02x}"
# 打开蜂鸣器
# Data Length: 00 02 (大端序)
# Data: cd 01
data_len = bytes([0x00, 0x02])
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
# Data Length: 00 02 (大端序)
# Data: cc 08
data_len = bytes([0x00, 0x02])
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 00 06 00 02 00 01 c0 c1 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x02, 0x00, 0x01, 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 00 07 00 02 00 02 cd 01 ce 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 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 00 07 00 02 00 02 cd 00 cf 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 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 00 07 00 02 00 02 cc 08 c6 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 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 00 07 00 02 00 02 0f 02 0f 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 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)
# Data: ce bb 00 22 00 00 22 7e (8 bytes)
# Frame Length: 00 0d (大端序, 13)
# Data Length: 00 08 (大端序)
# Checksum: 00 ^ 08 ^ ce ^ bb ^ 00 ^ 22 ^ 00 ^ 00 ^ 22 ^ 7e = 03
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x02, 0x00, 0x08,
0xce, 0xbb, 0x00, 0x22, 0x00, 0x00, 0x22, 0x7e, 0x03, 0x03])
print(f"读取EPC帧 (前21字节): {frame[:21].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:21] == expected, f"读取EPC帧不匹配"
print("读取EPC帧测试通过!")
# 测试打开射频命令
cmd = cmd_rf_power(True)
frame = build_setreq_frame(cmd)
# Data: 90 01 (2 bytes)
# Data Length: 00 02
# Frame Length: 00 07
# Checksum: 00 ^ 02 ^ 90 ^ 01 = 93
expected = bytes([0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x02, 0x00, 0x02, 0x90, 0x01, 0x93, 0x03])
print(f"打开射频帧 (前15字节): {frame[:15].hex()}")
print(f"期望: {expected.hex()}")
assert frame[:15] == expected, f"打开射频帧不匹配"
print("打开射频帧测试通过!")
def test_parse_getres_frame():
"""测试响应帧解析(大端序)"""
print("\n=== 测试响应帧解析(大端序)===")
# 模拟读版本号成功的响应
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) + 1 # constant + data_len + status + version + checksum
response.extend(frame_len.to_bytes(2, 'big')) # Frame Length (大端序)
response.extend([0x00, 0x02]) # Constant
data_len = 1 + len(version_str)
response.extend(data_len.to_bytes(2, 'big')) # Data Length (大端序)
response.append(0x00) # Status = 成功
response.extend(version_str) # Version string
# 计算校验和
checksum = calc_outer_checksum(data_len.to_bytes(2, 'big'), 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_factory_reset()
print(f"恢复出厂设置命令: {cmd.hex()}")
assert cmd == bytes([0xcf]), f"恢复出厂设置命令应为 cf"
# 测试读取格式命令
cmd = cmd_read_format()
print(f"读取格式命令: {cmd.hex()}")
assert cmd == bytes([0x83]), f"读取格式命令应为 83"
# 测试设置格式命令
cmd = cmd_set_format()
print(f"设置格式命令: {cmd.hex()}")
assert cmd == bytes([0x82, 0x0f, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x00]), f"设置格式命令不匹配"
# 测试蜂鸣器命令
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_rf_power(True)
print(f"打开射频命令: {cmd.hex()}")
assert cmd == bytes([0x90, 0x01]), f"打开射频命令应为 90 01"
cmd = cmd_rf_power(False)
print(f"关闭射频命令: {cmd.hex()}")
assert cmd == bytes([0x90, 0x00]), f"关闭射频命令应为 90 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命令不匹配"
# 测试选中卡命令验证校验和计算包含Internal Length
epc_data = bytes([0x11, 0x22])
cmd = cmd_select_card(epc_data)
print(f"选中卡命令 (EPC=1122): {cmd.hex()}")
# 根据协议: ce bb 00 0c 00 09 01 00 00 00 20 10 00 11 22 79 7e
# Checksum = 00+0c+00+09+01+00+00+00+20+10+00+11+22 mod 256 = 79
expected = bytes([0xce, 0xbb, 0x00, 0x0c, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x11, 0x22, 0x79, 0x7e])
assert cmd == expected, f"选中卡命令不匹配: 期望 {expected.hex()}, 实际 {cmd.hex()}"
print("命令生成函数测试通过!")
def test_epc_operations():
"""测试EPC操作命令"""
print("\n=== 测试EPC操作命令 ===")
# 测试选中卡命令
epc_data = bytes([0x11, 0x22])
cmd = cmd_select_card(epc_data)
print(f"选中卡命令: {cmd.hex()}")
# 验证结构: ce bb + Card Op Command + Internal Length(大端) + Payload + Checksum + 7e
assert cmd[0:2] == bytes([0xce, 0xbb]), "Command/Magic不正确"
assert cmd[2:4] == bytes([0x00, 0x0c]), "Card Op Command不正确"
assert cmd[4:6] == bytes([0x00, 0x09]), "Internal Length应为00 09 (大端序)"
assert cmd[-1] == 0x7e, "End Marker应为7e"
print("选中卡命令测试通过!")
# 测试写入EPC命令
old_epc_crc = bytes([0xca, 0x9e]) # 大端序
new_epc = bytes([0x11, 0x23])
cmd = cmd_write_epc(old_epc_crc, new_epc)
print(f"写入EPC命令: {cmd.hex()}")
# 验证结构
assert cmd[0:2] == bytes([0xce, 0xbb]), "Command/Magic不正确"
assert cmd[2:4] == bytes([0x00, 0x49]), "Card Op Command不正确"
assert cmd[-1] == 0x7e, "End Marker应为7e"
print("写入EPC命令测试通过!")
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()
test_epc_operations()
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())