package com.zy.service;
|
|
import com.zy.core.model.RFIDSlave;
|
import com.zy.core.properties.SlaveProperties;
|
import com.rfid.uhf288.RFIDTemplate;
|
import com.rfid.uhf288.RFIDTemplate.TagInfo;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.PostConstruct;
|
import java.util.ArrayList;
|
import java.util.List;
|
import java.util.Map;
|
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
|
/**
|
* RFID自动连接和监控服务
|
* 支持多个RFID设备独立管理,每个设备独立的连接线程和检测线程
|
* 每个设备的autoConnect配置独立控制
|
*
|
* @author Created on 2026/01/10
|
*/
|
@Slf4j
|
@Service
|
public class RFIDAutoConnectService {
|
|
@Autowired
|
private SlaveProperties slaveProperties;
|
|
@Value("${wcs-slave.rfid-config.reconnectInterval:5}")
|
private Integer globalReconnectInterval;
|
|
@Value("${wcs-slave.rfid-config.tagScanInterval:500}")
|
private Integer globalTagScanInterval;
|
|
@Value("${wcs-slave.rfid-config.tagScanTime:10}")
|
private Integer globalTagScanTime;
|
|
// 存储每个设备的连接和线程信息
|
private final Map<Integer, DeviceManager> deviceManagers = new ConcurrentHashMap<>();
|
|
/**
|
* 设备管理器 - 管理单个RFID设备的连接和检测
|
*/
|
private static class DeviceManager {
|
final RFIDSlave config;
|
final RFIDTemplate template;
|
final AtomicBoolean running = new AtomicBoolean(false);
|
final AtomicBoolean connected = new AtomicBoolean(false);
|
Thread connectThread;
|
Thread scanThread;
|
final int reconnectInterval;
|
final long tagScanInterval;
|
final int tagScanTime;
|
int reconfigCounter = 0;
|
volatile List<TagInfo> latestTags = new ArrayList<>(); // 最新检测到的标签
|
|
DeviceManager(RFIDSlave config, Integer reconnectInterval, Integer tagScanInterval, Integer tagScanTime) {
|
this.config = config;
|
this.template = new RFIDTemplate();
|
this.reconnectInterval = reconnectInterval != null ? reconnectInterval : 5;
|
this.tagScanInterval = tagScanInterval != null ? tagScanInterval : 500;
|
this.tagScanTime = tagScanTime != null ? tagScanTime : 10;
|
}
|
|
void start() {
|
if (running.get()) {
|
return;
|
}
|
|
running.set(true);
|
|
// 启动连接线程
|
// 注意:设置为非守护线程,确保应用运行期间线程一直运行
|
connectThread = new Thread(this::connectLoop,
|
String.format("RFID-Connect-%d-%s", config.getId(), config.getIp()));
|
connectThread.setDaemon(false); // 改为非守护线程,确保应用运行期间一直运行
|
connectThread.start();
|
|
// 启动标签检测线程
|
scanThread = new Thread(this::scanLoop,
|
String.format("RFID-Scan-%d-%s", config.getId(), config.getIp()));
|
scanThread.setDaemon(false); // 改为非守护线程,确保应用运行期间一直运行
|
scanThread.start();
|
}
|
|
void stop() {
|
running.set(false);
|
connected.set(false);
|
|
if (connectThread != null) {
|
connectThread.interrupt();
|
}
|
if (scanThread != null) {
|
scanThread.interrupt();
|
}
|
|
try {
|
if (connectThread != null) {
|
connectThread.join(2000);
|
}
|
if (scanThread != null) {
|
scanThread.join(2000);
|
}
|
} catch (InterruptedException e) {
|
Thread.currentThread().interrupt();
|
}
|
|
if (template != null && template.isConnected()) {
|
try {
|
template.disconnect();
|
} catch (Exception e) {
|
log.error("RFID设备[{}]断开连接异常", config.getId(), e);
|
}
|
}
|
}
|
|
/**
|
* 连接循环 - 负责连接和重连
|
* 特别处理UnsatisfiedLinkError,确保DLL方法链接失败时也会定期重连
|
*/
|
private void connectLoop() {
|
log.info("RFID设备[{}]连接线程启动 - IP: {}, Port: {}",
|
config.getId(), config.getIp(), config.getPort());
|
|
while (running.get()) {
|
try {
|
if (!connected.get()) {
|
log.info("========== RFID设备[{}]尝试连接 ==========", config.getId());
|
log.info("IP: {}, Port: {}", config.getIp(), config.getPort());
|
|
// 尝试连接
|
boolean success = false;
|
try {
|
success = template.connectNetwork(config.getIp(), config.getPort());
|
} catch (UnsatisfiedLinkError e) {
|
// DLL方法链接失败,记录错误但继续重连
|
log.error("RFID设备[{}] DLL方法链接失败 - UnsatisfiedLinkError", config.getId());
|
log.error("错误信息: {}", e.getMessage());
|
log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
|
log.warn("将在{}秒后重试连接", reconnectInterval);
|
success = false;
|
}
|
|
if (success) {
|
connected.set(true);
|
log.info("✓ RFID设备[{}]连接成功!IP: {}, Port: {}",
|
config.getId(), config.getIp(), config.getPort());
|
} else {
|
log.warn("✗ RFID设备[{}]连接失败,{}秒后重试",
|
config.getId(), reconnectInterval);
|
Thread.sleep(reconnectInterval * 1000L);
|
}
|
} else {
|
// 已连接,检查连接状态
|
if (!template.isConnected()) {
|
log.warn("RFID设备[{}]连接已断开,准备重连", config.getId());
|
connected.set(false);
|
} else {
|
// 连接正常,定期重新配置天线(处理天线插拔情况)
|
// 每5次循环(约50秒)重新配置一次天线,确保插拔后能自动检测
|
reconfigCounter++;
|
if (reconfigCounter >= 5) {
|
reconfigCounter = 0;
|
log.debug("RFID设备[{}]定期重新配置天线(处理天线插拔)", config.getId());
|
boolean reconfigured = template.reconfigureAntenna();
|
if (reconfigured) {
|
// log.info("RFID设备[{}]天线重新配置成功,所有天线已启用", config.getId());
|
}
|
}
|
|
// 等待一段时间后再次检查
|
Thread.sleep(reconnectInterval * 1000L);
|
}
|
}
|
} catch (InterruptedException e) {
|
log.info("RFID设备[{}]连接线程被中断", config.getId());
|
Thread.currentThread().interrupt();
|
break;
|
} catch (UnsatisfiedLinkError e) {
|
// DLL方法链接失败,记录错误并继续重连
|
log.error("RFID设备[{}]连接线程 - DLL方法链接失败", config.getId());
|
log.error("错误信息: {}", e.getMessage());
|
log.error("可能原因:1. DLL版本不匹配 2. 方法签名不匹配 3. DLL未正确加载");
|
log.warn("将在{}秒后重试连接", reconnectInterval);
|
connected.set(false);
|
try {
|
Thread.sleep(reconnectInterval * 1000L);
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
} catch (Exception e) {
|
log.error("RFID设备[{}]连接线程异常", config.getId(), e);
|
connected.set(false);
|
try {
|
Thread.sleep(reconnectInterval * 1000L);
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
}
|
}
|
|
log.info("RFID设备[{}]连接线程已停止", config.getId());
|
}
|
|
/**
|
* 标签检测循环 - 持续检测并打印标签
|
* 特别处理UnsatisfiedLinkError,确保DLL方法链接失败时不影响重连
|
*/
|
private void scanLoop() {
|
log.info("RFID设备[{}]标签检测线程启动 - IP: {}", config.getId(), config.getIp());
|
|
while (running.get()) {
|
try {
|
if (connected.get() && template.isConnected()) {
|
try {
|
List<TagInfo> tags = template.readTags(4, 0, tagScanTime);
|
latestTags = tags != null ? new ArrayList<>(tags) : new ArrayList<>();
|
|
if (tags != null && !tags.isEmpty()) {
|
printTags(tags);
|
}
|
} catch (UnsatisfiedLinkError e) {
|
// DLL方法链接失败,标记为未连接,让连接线程重连
|
log.error("RFID设备[{}]标签检测 - DLL方法链接失败", config.getId());
|
log.error("错误信息: {}", e.getMessage());
|
log.warn("连接状态已标记为断开,连接线程将尝试重连");
|
connected.set(false);
|
// 等待一段时间后继续
|
Thread.sleep(reconnectInterval * 1000L);
|
continue;
|
}
|
} else {
|
// 未连接,等待一段时间
|
Thread.sleep(1000);
|
}
|
|
// 等待指定间隔
|
Thread.sleep(tagScanInterval);
|
} catch (InterruptedException e) {
|
log.info("RFID设备[{}]标签检测线程被中断", config.getId());
|
Thread.currentThread().interrupt();
|
break;
|
} catch (UnsatisfiedLinkError e) {
|
// DLL方法链接失败,标记为未连接
|
log.error("RFID设备[{}]标签检测线程 - DLL方法链接失败", config.getId());
|
log.error("错误信息: {}", e.getMessage());
|
connected.set(false);
|
try {
|
Thread.sleep(reconnectInterval * 1000L);
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
} catch (Exception e) {
|
log.error("RFID设备[{}]标签检测线程异常", config.getId(), e);
|
try {
|
Thread.sleep(1000);
|
} catch (InterruptedException ie) {
|
Thread.currentThread().interrupt();
|
break;
|
}
|
}
|
}
|
|
log.info("RFID设备[{}]标签检测线程已停止", config.getId());
|
}
|
|
private void printTags(List<TagInfo> tags) {
|
if (tags == null || tags.isEmpty()) {
|
return;
|
}
|
for (TagInfo tag : tags) {
|
log.info("RFID设备[{}]检测到标签: EPC={}, RSSI={}dBm, 天线={}",
|
config.getId(), tag.epc, tag.rssi, tag.antenna);
|
}
|
}
|
}
|
|
/**
|
* 系统启动时初始化所有配置了autoConnect=true的设备
|
*/
|
@PostConstruct
|
public void init() {
|
log.info("========== RFID自动连接服务启动 ==========");
|
|
if (slaveProperties.getRfid() == null || slaveProperties.getRfid().isEmpty()) {
|
log.info("未配置RFID设备");
|
return;
|
}
|
|
log.info("RFID全局配置 - 重连间隔: {}秒, 检测间隔: {}毫秒, 扫描时间: {} * 100ms",
|
globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
|
|
// 遍历所有RFID设备配置
|
for (RFIDSlave rfidConfigItem : slaveProperties.getRfid()) {
|
if (rfidConfigItem == null) {
|
continue;
|
}
|
|
// 检查是否启用自动连接
|
Boolean autoConnect = rfidConfigItem.getAutoConnect();
|
if (autoConnect == null || !autoConnect) {
|
log.info("RFID设备[{}] - IP: {}, Port: {} - 未启用自动连接",
|
rfidConfigItem.getId(), rfidConfigItem.getIp(), rfidConfigItem.getPort());
|
continue;
|
}
|
|
// 验证配置
|
if (rfidConfigItem.getIp() == null || rfidConfigItem.getPort() == null) {
|
log.warn("RFID设备[{}]配置不完整,跳过自动连接", rfidConfigItem.getId());
|
continue;
|
}
|
|
// 创建设备管理器并启动
|
DeviceManager manager = new DeviceManager(rfidConfigItem,
|
globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
|
deviceManagers.put(rfidConfigItem.getId(), manager);
|
manager.start();
|
|
log.info("RFID设备[{}]自动连接已启动 - IP: {}, Port: {}",
|
rfidConfigItem.getId(), rfidConfigItem.getIp(), rfidConfigItem.getPort());
|
}
|
|
log.info("RFID自动连接服务已启动,共 {} 个设备启用自动连接", deviceManagers.size());
|
}
|
|
/**
|
* 手动停止所有RFID设备连接(通过API调用)
|
* 注意:移除了@PreDestroy,服务不会自动关闭,只能通过API手动关闭
|
*/
|
public void stopAll() {
|
log.info("========== RFID自动连接服务手动关闭 ==========");
|
|
// 停止所有设备管理器
|
for (Map.Entry<Integer, DeviceManager> entry : deviceManagers.entrySet()) {
|
try {
|
log.info("停止RFID设备[{}]自动连接", entry.getKey());
|
entry.getValue().stop();
|
} catch (Exception e) {
|
log.error("停止RFID设备[{}]自动连接异常", entry.getKey(), e);
|
}
|
}
|
|
deviceManagers.clear();
|
log.info("RFID自动连接服务已关闭");
|
}
|
|
/**
|
* 手动停止指定RFID设备连接(通过API调用)
|
*/
|
public boolean stopDevice(Integer deviceId) {
|
DeviceManager manager = deviceManagers.get(deviceId);
|
if (manager == null) {
|
log.warn("RFID设备[{}]未启用自动连接或不存在", deviceId);
|
return false;
|
}
|
|
try {
|
log.info("手动停止RFID设备[{}]自动连接", deviceId);
|
manager.stop();
|
deviceManagers.remove(deviceId);
|
return true;
|
} catch (Exception e) {
|
log.error("停止RFID设备[{}]自动连接异常", deviceId, e);
|
return false;
|
}
|
}
|
|
/**
|
* 手动启动指定RFID设备连接(通过API调用)
|
*/
|
public boolean startDevice(Integer deviceId) {
|
// 检查设备是否已经在运行
|
if (deviceManagers.containsKey(deviceId)) {
|
DeviceManager manager = deviceManagers.get(deviceId);
|
if (manager.running.get()) {
|
log.warn("RFID设备[{}]已经在运行", deviceId);
|
return false;
|
}
|
}
|
|
// 查找配置
|
RFIDSlave config = null;
|
for (RFIDSlave rfidConfigItem : slaveProperties.getRfid()) {
|
if (rfidConfigItem != null && rfidConfigItem.getId().equals(deviceId)) {
|
config = rfidConfigItem;
|
break;
|
}
|
}
|
|
if (config == null) {
|
log.warn("RFID设备[{}]配置不存在", deviceId);
|
return false;
|
}
|
|
// 验证配置
|
if (config.getIp() == null || config.getPort() == null) {
|
log.warn("RFID设备[{}]配置不完整", deviceId);
|
return false;
|
}
|
|
// 创建设备管理器并启动
|
DeviceManager manager = new DeviceManager(config,
|
globalReconnectInterval, globalTagScanInterval, globalTagScanTime);
|
deviceManagers.put(deviceId, manager);
|
manager.start();
|
|
log.info("RFID设备[{}]手动启动成功 - IP: {}, Port: {}",
|
deviceId, config.getIp(), config.getPort());
|
return true;
|
}
|
|
/**
|
* 获取设备连接状态
|
*/
|
public Map<String, Object> getDeviceStatus(Integer deviceId) {
|
Map<String, Object> result = new java.util.HashMap<>();
|
|
DeviceManager manager = deviceManagers.get(deviceId);
|
if (manager == null) {
|
result.put("exists", false);
|
result.put("message", "设备未启用自动连接");
|
return result;
|
}
|
|
result.put("exists", true);
|
result.put("connected", manager.connected.get());
|
result.put("running", manager.running.get());
|
result.put("ip", manager.config.getIp());
|
result.put("port", manager.config.getPort());
|
result.put("templateConnected", manager.template.isConnected());
|
|
return result;
|
}
|
|
/**
|
* 获取所有设备状态
|
*/
|
public List<Map<String, Object>> getAllDeviceStatus() {
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
for (Map.Entry<Integer, DeviceManager> entry : deviceManagers.entrySet()) {
|
Map<String, Object> status = getDeviceStatus(entry.getKey());
|
status.put("deviceId", entry.getKey());
|
result.add(status);
|
}
|
|
return result;
|
}
|
|
/**
|
* 重新配置指定设备的天线(用于天线插拔后重新配置)
|
*/
|
public boolean reconfigureAntenna(Integer deviceId) {
|
DeviceManager manager = deviceManagers.get(deviceId);
|
if (manager == null) {
|
log.warn("RFID设备[{}]未启用自动连接或不存在", deviceId);
|
return false;
|
}
|
|
if (!manager.template.isConnected()) {
|
log.warn("RFID设备[{}]未连接,无法配置天线", deviceId);
|
return false;
|
}
|
|
log.info("手动重新配置RFID设备[{}]天线", deviceId);
|
return manager.template.reconfigureAntenna();
|
}
|
|
public List<Map<String, Object>> getDeviceTags(Integer deviceId, String ip, Integer antenna) {
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
DeviceManager manager = null;
|
if (ip != null && !ip.isEmpty()) {
|
for (DeviceManager m : deviceManagers.values()) {
|
if (ip.equals(m.config.getIp())) {
|
manager = m;
|
break;
|
}
|
}
|
} else if (deviceId != null) {
|
manager = deviceManagers.get(deviceId);
|
}
|
|
if (manager == null || !manager.connected.get() || !manager.template.isConnected()) {
|
return result;
|
}
|
|
List<TagInfo> tags = manager.latestTags;
|
if (tags == null || tags.isEmpty()) {
|
return result;
|
}
|
|
for (TagInfo tag : tags) {
|
if (antenna != null && tag.antenna != antenna) {
|
continue;
|
}
|
Map<String, Object> tagMap = new java.util.HashMap<>();
|
tagMap.put("epc", tag.epc);
|
tagMap.put("rssi", tag.rssi);
|
tagMap.put("antenna", tag.antenna);
|
tagMap.put("timestamp", tag.timestamp);
|
tagMap.put("deviceId", manager.config.getId());
|
tagMap.put("deviceIp", manager.config.getIp());
|
result.add(tagMap);
|
}
|
return result;
|
}
|
|
public List<Map<String, Object>> queryDeviceTags(Integer deviceId, String ip, Integer antenna) {
|
List<Map<String, Object>> result = new ArrayList<>();
|
|
DeviceManager manager = null;
|
if (ip != null && !ip.isEmpty()) {
|
for (DeviceManager m : deviceManagers.values()) {
|
if (ip.equals(m.config.getIp())) {
|
manager = m;
|
break;
|
}
|
}
|
} else if (deviceId != null) {
|
manager = deviceManagers.get(deviceId);
|
}
|
|
if (manager == null || !manager.connected.get() || !manager.template.isConnected()) {
|
return result;
|
}
|
|
try {
|
List<TagInfo> tags = manager.template.readTags(4, 0, manager.tagScanTime);
|
if (tags != null && !tags.isEmpty()) {
|
for (TagInfo tag : tags) {
|
if (antenna != null && tag.antenna != antenna) {
|
continue;
|
}
|
Map<String, Object> tagMap = new java.util.HashMap<>();
|
tagMap.put("epc", tag.epc);
|
tagMap.put("rssi", tag.rssi);
|
tagMap.put("antenna", tag.antenna);
|
tagMap.put("timestamp", tag.timestamp);
|
tagMap.put("deviceId", manager.config.getId());
|
tagMap.put("deviceIp", manager.config.getIp());
|
result.add(tagMap);
|
}
|
}
|
} catch (Exception e) {
|
log.error("查询RFID设备[{}]标签异常", deviceId != null ? deviceId : ip, e);
|
}
|
return result;
|
}
|
}
|