This commit is contained in:
2026-04-15 09:30:07 +08:00
parent 7e9f9b5f25
commit a9f0b97d26
3 changed files with 534 additions and 292 deletions

View File

@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
测试 MT6 RFID 读卡器协议函数
测试 MT6 RFID 读卡器协议函数(大端序版本)
"""
import sys
@@ -16,7 +16,11 @@ from rfid_tester import (
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,
@@ -29,28 +33,28 @@ def test_calc_outer_checksum():
"""测试校验和计算"""
print("\n=== 测试校验和计算 ===")
# 根据文档,读版本号命令的校验和应该是 0xc1
# Data Length: 01 00 (端序)
# 根据文档,读版本号命令
# Data Length: 00 01 (端序)
# Data: c0
data_len = bytes([0x01, 0x00])
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}"
# 打开蜂鸣器的校验和应该是 0xce
# Data Length: 02 00
# 打开蜂鸣器
# Data Length: 00 02 (大端序)
# Data: cd 01
data_len = bytes([0x02, 0x00])
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的校验和应该是 0xc6
# Data Length: 02 00
# 设置功率=8
# Data Length: 00 02 (大端序)
# Data: cc 08
data_len = bytes([0x02, 0x00])
data_len = bytes([0x00, 0x02])
data = bytes([0xcc, 0x08])
checksum = calc_outer_checksum(data_len, data)
print(f"设置功率=8校验和: 0x{checksum:02x} (期望: 0xc6)")
@@ -60,14 +64,14 @@ def test_calc_outer_checksum():
def test_build_setreq_frame():
"""测试帧构建"""
print("\n=== 测试帧构建 ===")
"""测试帧构建(大端序)"""
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])
# 大端序: 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"读版本号帧不匹配"
@@ -77,8 +81,8 @@ def test_build_setreq_frame():
# 测试打开蜂鸣器命令
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])
# 大端序: 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"打开蜂鸣器帧不匹配"
@@ -87,8 +91,8 @@ def test_build_setreq_frame():
# 测试关闭蜂鸣器命令
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])
# 大端序: 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"关闭蜂鸣器帧不匹配"
@@ -97,8 +101,8 @@ def test_build_setreq_frame():
# 测试设置功率命令
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])
# 大端序: 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"设置功率帧不匹配"
@@ -107,8 +111,8 @@ def test_build_setreq_frame():
# 测试设置被动模式命令
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])
# 大端序: 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"设置模式帧不匹配"
@@ -117,34 +121,49 @@ def test_build_setreq_frame():
# 测试读取 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"
# 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=== 测试响应帧解析 ===")
"""测试响应帧解析(大端序)"""
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
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, 'little')) # Data Length
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, 'little'), bytes([0x00]) + version_str)
checksum = calc_outer_checksum(data_len.to_bytes(2, 'big'), bytes([0x00]) + version_str)
response.append(checksum)
response.append(0x03) # End Marker
@@ -167,6 +186,21 @@ def test_command_functions():
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()}")
@@ -176,6 +210,15 @@ def test_command_functions():
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()}")
@@ -195,13 +238,49 @@ def test_command_functions():
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("MT6 RFID 读卡器协议函数测试(大端序版本)")
print("=" * 60)
try:
@@ -209,6 +288,7 @@ def main():
test_build_setreq_frame()
test_parse_getres_frame()
test_command_functions()
test_epc_operations()
print("\n" + "=" * 60)
print("所有测试通过!")