This commit is contained in:
2025-10-24 14:55:58 +08:00
parent afdefbaca6
commit 93d412b8fe
11 changed files with 7486 additions and 0 deletions

View File

@ -0,0 +1,513 @@
import socket
import threading
import time
import binascii
from typing import Optional, Callable, Dict, Any, Set
from collections import Counter
from .crc16 import crc16
from .command_hex import command_hex
class rfid_service:
"""
RFID读写器服务
"""
def __init__(self, host='192.168.1.190', port=6000):
"""
初始化RFID控制器
参数:
host: RFID读写器IP地址
port: RFID读写器端口号
"""
self.host = host
self.port = port
self._thread_signal = False
self._receive_thread = None
self._callback = None
self._pause_receive = False
self._data_buffer = [] # 收到推送的数据
self._last_collect_time = None
self._data_lock = threading.Lock() # 用于保护数据缓冲区的锁
# 需要过滤掉的数据(字符串)
self._filter_value = None
self.check_time_seconds = 60.0 # 采集数据时间(秒)
# 超时设置
self._connect_timeout = 5.0 # 连接超时时间(秒)
self.client_socket = None
self.connected = False
#链接失败次数
self._error_count = 0
# #30个字(读卡器工作模式中设定)+2字节CRC+4字节 len+0x00+oxEE+0x00
self._buffer_length=66
#设置读取命令设置时连接最大次数
self._max_command_count=3
def CreatConnect(self)->bool:
try:
if self.client_socket:
self.client_socket.close()
self.connected = False
self.client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.client_socket.settimeout(self._connect_timeout)
print(f"准备连接RFID读写器")
self.client_socket.connect((self.host, self.port))
self.connected = True
print(f"成功连接到RFID读写器: {self.host}:{self.port}")
self._error_count = 0 # 重置错误计数
return True
except Exception as e:
print(f"连接RFID读写器失败: {e}")
self.connected = False
self._error_count += 1
return False
def connect(self) -> bool:
"""
连接到RFID读写器
返回:
bool: 连接成功返回True失败返回False
"""
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(self._connect_timeout)
sock.connect((self.host, self.port))
print(f"成功连接到RFID读写器: {self.host}:{self.port}")
return True
except Exception as e:
print(f"连接RFID读写器失败: {e}")
return False
def _send_command(self, command_data: bytes) -> Optional[bytes]:
"""
发送命令到RFID读写器并等待响应
参数:
command_data: 要发送的命令字节数据
返回:
bytes: 读写器响应数据如果失败返回None
"""
for i in range(self._max_command_count):
try:
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
sock.settimeout(self._connect_timeout) # 设置连接超时
sock.connect((self.host, self.port))
sock.send(command_data)
response = sock.recv(1024)
print(f"收到RFID响应: {binascii.hexlify(response).decode()}")
return response
except socket.timeout:
if i==self._max_command_count-1:
print(f"RFID命令响应超时,已达最大重试次数: {self._max_command_count}")
return None
else:
print(f"RFID命令响应超时 (超时设置: {self._connect_timeout}秒,)重连中.")
except Exception as e:
print(f"RFID命令发送错误: {e}")
if i==self._max_command_count-1:
print(f"RFID命令发送错误,已达最大重试次数: {self._max_command_count}")
return None
#region ======= 配置命令封装 =======
def set_working_mode(self, address: int, mode_params: Dict[str, Any]) -> bool:
"""
设置工作模式
参数:
address: 读写器地址
mode_params: 工作模式参数字典,包含以下键:
- read_mode: 读取模式 (0x00-0x03),0应答模式,1为主动模式,2触发模式(低电平有效),3触发模式(高电平有效)
- mode_state: Bit1=0时韦根输出Bit1=1时RS232输出,Bit2=0时开蜂鸣器提示Bit2=1时关蜂鸣器提示.
- mem_inven: 0x00保留区0x01EPC存储器0x02TID存储器0x03用户存储器0x04多张查询0x05单张查询。0x06多张TID询查
- first_adr: 第一个地址 (0x00-0xFF)
- word_num: 字数量Word_Num不能超过3
- tag_time: 主动模式下标签输出间隔时间(0~255)*1s对同一张标签在间隔时间内只输出一次
返回:
bool: 设置成功返回True失败返回False
"""
try:
# 构建命令
command = command_hex.build_set_mode_command(
address=address,
# wg_mode=mode_params.get('wg_mode', 0),
# wg_data_interval=mode_params.get('wg_data_interval', 0),
# wg_pulse_width=mode_params.get('wg_pulse_width', 0),
# wg_pulse_interval=mode_params.get('wg_pulse_interval', 0),
read_mode=mode_params.get('read_mode', 1),
mode_state=mode_params.get('mode_state', 2), #开蜂鸣器提示1为不开
mem_inven=mode_params.get('mem_inven', 3),
first_adr=mode_params.get('first_adr', 0),
word_num=mode_params.get('word_num', 30),
tag_filt_time=mode_params.get('tag_filt_time', 0)
)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
return command_hex.parse_set_mode_hex(response)
except Exception as e:
print(f"解析设置响应错误: {e}")
return False
return False
except Exception as e:
print(f"设置工作模式错误: {e}")
return False
def read_working_mode(self, address: int) -> Optional[Dict[str, Any]]:
"""
读取工作模式
参数:
address: 读写器地址
返回:
dict: 工作模式参数如果失败返回None
"""
try:
# 构建命令
command = command_hex.build_read_mode_command(address=address)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
return command_hex.parse_read_mode_hex(response)
except Exception as e:
print(f"解析读取响应错误: {e}")
return None
return None
except Exception as e:
print(f"读取工作模式错误: {e}")
return None
def set_power(self, address: int, power_value: int) -> bool:
"""
设置读写器功率
参数:
address: 读写器地址
power_value: 功率值 (0-26 dBm)
返回:
bool: 设置成功返回True失败返回False
"""
try:
# 构建命令
command =command_hex.build_set_power_command(address=address, power_value=power_value)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
return command_hex.parse_set_power_hex(response)
except Exception as e:
print(f"解析功率设置响应错误: {e}")
return False
return False
except Exception as e:
print(f"设置功率错误: {e}")
return False
def set_trigger_delay(self, address: int, delay_time: int) -> bool:
"""
设置触发延时
参数:
address: 读写器地址
delay_time: 延时时间 (0-254秒255表示读取参数)
返回:
bool: 设置成功返回True失败返回False
"""
try:
# 构建命令
command = command_hex.build_trigger_delay_command(address=address, delay_time=delay_time)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
if delay_time == 255:
# 读取模式
current_delay = command_hex.parse_trigger_delay_hex(response)
print(f"当前触发延时: {current_delay}")
return True
else:
# 设置模式
return True # 如果发送成功且没有异常,认为设置成功
except Exception as e:
print(f"解析触发延时响应错误: {e}")
return False
return False
except Exception as e:
print(f"设置触发延时错误: {e}")
return False
def set_read_interval(self, address: int, interval_time: int) -> bool:
"""
设置主动模式读卡间隔
参数:
address: 读写器地址
interval_time: 读卡间隔 (0-254毫秒255表示读取参数)
返回:
bool: 设置成功返回True失败返回False
"""
try:
# 构建命令
command = command_hex.build_set_readinterval_command(address=address, delay_time=interval_time)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
return command_hex.parse_set_readinterval_hex(response)
except Exception as e:
print(f"解析读卡间隔响应错误: {e}")
return False
return False
except Exception as e:
print(f"设置读卡间隔错误: {e}")
return False
def get_read_interval(self, address: int) -> int:
"""
设置主动模式读卡间隔
参数:
address: 读写器地址
返回:
int: 当前读卡间隔0-254毫秒如果失败返回-1
"""
try:
# 构建命令
command = command_hex.build_set_readinterval_command(address=address, delay_time=255)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
loc_suc= command_hex.parse_set_readinterval_hex(response)
if loc_suc:
return response[4]
else:
return -1
except Exception as e:
print(f"解析读卡间隔响应错误: {e}")
return False
return False
except Exception as e:
print(f"设置读卡间隔错误: {e}")
return False
def read_reader_info(self, address: int) -> Optional[Dict[str, Any]]:
"""
读取读写器信息
参数:
address: 读写器地址
返回:
dict: 读写器信息如果失败返回None
"""
try:
# 构建读取读写器信息的命令
command = command_hex.build_reader_info_command(address=address)
# 发送命令
response = self._send_command(command)
if response:
# 解析响应
try:
return command_hex.parse_reader_info_hex(response)
except Exception as e:
print(f"解析读写器信息响应错误: {e}")
return None
return None
except Exception as e:
print(f"读取读写器信息错误: {e}")
return None
#endregion
def start_receiver(self, callback: Optional[Callable[[str], None]] = None)->bool:
"""
开始接收RFID推送的数据
参数:
callback: 接收数据的回调函数参数为收集到的RFID字符串数据
"""
if self._thread_signal:
print("RFID数据接收已经在运行")
return True
self._callback = callback
if self.CreatConnect():
self._thread_signal = True
# 清空数据缓冲区
with self._data_lock:
self._data_buffer.clear()
self._receive_thread = threading.Thread(target=self._run, daemon=True,name="RFID_Receive")
self._receive_thread.start()
print("RFID数据接收已启动")
return True
else:
print("RFID数据接收启动失败")
return False
def _run(self):
"""
接收线程的主循环用于接收RFID推送的数据
"""
while self._thread_signal:
if self._pause_receive:
time.sleep(1)
continue
# 重置数据收集时间
self._last_collect_time = time.time()
while time.time() - self._last_collect_time < self.check_time_seconds:
# 持续接收数据
try:
# 使用缓冲区累积接收数据,正确处理固定长度数据包
received_data = b""
remaining_bytes = self._buffer_length
while remaining_bytes > 0:
chunk = self.client_socket.recv(remaining_bytes)
# 检查连接是否关闭
if not chunk:
print(f"[连接关闭] 接收过程中连接已关闭,已接收 {len(received_data)} 字节,预期 {self._buffer_length} 字节")
if not self.CreatConnect():
print(f"[连接断开] 重连失败,已累计失败 {self._error_count}等待1秒后重试")
time.sleep(1)
break
received_data += chunk
remaining_bytes -= len(chunk)
print(f"[数据接收] 已接收 {len(received_data)}/{self._buffer_length} 字节")
# 只有接收到完整的数据才算成功
if remaining_bytes == 0:
print(f"[数据接收] 成功接收完整数据包 ({self._buffer_length} 字节)")
data = received_data # 保存完整的数据包
self._error_count=0
else:
continue # 没有接收到任何数据,继续下一次循环
except (ConnectionResetError, ConnectionAbortedError, BrokenPipeError) as e:
# 明确区分连接断开情况
print(f"[连接断开] 网络连接已断开,错误类型: {type(e).__name__},错误详情: {e}")
# 尝试重新连接,但避免频繁重连
if not self.CreatConnect():
print(f"[连接断开] 重连失败,已累计失败 {self._error_count}等待1秒后重试")
time.sleep(1)
continue # 继续下一次循环
except socket.timeout:
# 明确区分超时情况
print(f"[超时] 接收数据超时,当前时间: {time.strftime('%Y-%m-%d %H:%M:%S')}")
# 超时不重置连接,继续等待
continue # 超时继续下一次循环
except Exception as e:
# 记录其他类型的异常
print(f"[其他错误] RFID数据接收错误错误类型: {type(e).__name__},错误详情: {e}")
# 判断是否可能是连接问题
if isinstance(e, (OSError, IOError)) and '远程主机强迫关闭了一个现有的连接' in str(e):
print("[其他错误] 错误原因疑似连接断开,将尝试重新连接")
self.CreatConnect()
time.sleep(1)
continue # 其他错误继续下一次循环
if data:
loc_str = command_hex.parse_user_data_hex(data)
print(f"收到RFID推送数据: {binascii.hexlify(data).decode()}")
if loc_str:
# 将数据添加到缓冲区
with self._data_lock:
if self._filter_value == loc_str:
continue
self._data_buffer.append(loc_str)
self._pause_receive = True
self._process_collected_data()
def _process_collected_data(self):
"""
处理收集到的数据,过滤掉指定值,并调用回调函数
"""
with self._data_lock:
# 如果缓冲区有数据
if self._data_buffer and self._callback:
try:
# 统计数据缓冲区中各字符串出现的次数
# 这里self._data_buffer是字符串列表Counter会统计每个完整字符串出现的次数
counter = Counter(self._data_buffer)
# 处理空缓冲区情况避免IndexError
if counter:
# 获取出现次数最多的字符串及其出现次数
# most_common(1)返回[(most_common_string, count)]
most_common_string, count = counter.most_common(1)[0]
print(f"出现次数最多的字符串是: '{most_common_string}', 出现次数: {count}")
# 使用出现次数最多的字符串作为结果传递给回调
self._callback(most_common_string)
else:
# 空缓冲区情况
print("数据缓冲区为空")
self._callback(None)
print(f"收集了{len(self._data_buffer)}条RFID数据过滤后数据为{most_common_string}")
except Exception as e:
print(f"回调函数执行错误: {e}")
finally:
# 清空缓冲区
self._data_buffer.clear()
else:
print("未接收到数据")
# self._callback(None)
def __del__(self):
"""
析构函数,确保在对象销毁时关闭连接
"""
if self.client_socket:
self.client_socket.close()
self.client_socket = None
def stop_receiver(self):
"""
停止接收RFID推送的数据
"""
self._thread_signal = False
if self._receive_thread:
self._receive_thread.join(timeout=2.0)
print("RFID数据接收已停止")
# 关闭连接
if self.client_socket:
self.client_socket.close()
self.client_socket = None