| | |
| | | package chuankou; |
| | | import java.text.SimpleDateFormat; |
| | | import java.util.Date; |
| | | import java.util.concurrent.ConcurrentHashMap; |
| | | import java.util.concurrent.atomic.AtomicBoolean; |
| | | |
| | | import javax.swing.SwingWorker; |
| | | |
| | | import chushihua.lunxun; |
| | | import dialog.Charulog; |
| | | import dialog.Dingshidialog; |
| | | import dialog.Errlog; |
| | | import publicway.OpenDoor; |
| | | import xitongshezhi.SystemDebugDialog; |
| | | |
| | | /** |
| | | * 串口消息发送工具类 |
| | | * 提供高性能的串口消息发送功能,适合高频调用 |
| | | * 优化内存使用,避免长时间运行内存泄漏 |
| | | */ |
| | | public class Sendmsg { |
| | | // 静态串口服务实例 |
| | | private static volatile SerialPortService serialService = null; |
| | | private static volatile boolean isPortOpen = false; |
| | | private static final AtomicBoolean isPortOpen = new AtomicBoolean(false); |
| | | |
| | | // 改为非final,支持动态控制 |
| | | private static boolean DEBUG_MODE = false; |
| | | private static volatile boolean DEBUG_MODE = false; |
| | | |
| | | // 日期格式化 |
| | | private static final SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); |
| | | // 使用ThreadLocal保证SimpleDateFormat线程安全 |
| | | private static final ThreadLocal<SimpleDateFormat> TIME_FORMATTER = |
| | | ThreadLocal.withInitial(() -> new SimpleDateFormat("HH:mm:ss.SSS")); |
| | | |
| | | // 缓存字符串构建器,减少对象创建 |
| | | private static final ThreadLocal<StringBuilder> STRING_BUILDER_CACHE = |
| | | ThreadLocal.withInitial(() -> new StringBuilder(128)); |
| | | |
| | | // 记录活跃的SwingWorker,便于管理 |
| | | private static final ConcurrentHashMap<String, SwingWorker<?, ?>> ACTIVE_WORKERS = |
| | | new ConcurrentHashMap<>(); |
| | | |
| | | |
| | | /**发卡服务器控制打开某个柜门调用指令 |
| | | * @param int slotId柜门编号1-60 |
| | | * @param int type 1是服务器发卡,2是管理员发卡*/ |
| | | public static boolean opendoorzhiling(int slotId,int type) { |
| | | lunxun.setSendChaxunzhiling(false);//暂停查询指令 |
| | | |
| | | try { |
| | | // 调用OpenDoor生成开门指令 |
| | | String command = OpenDoor.openOneDoor(slotId, type); |
| | | boolean sendResult = Sendmsg.sendMessage(command); |
| | | |
| | | StringBuilder mesBuilder = STRING_BUILDER_CACHE.get(); |
| | | mesBuilder.setLength(0); // 清空重用 |
| | | mesBuilder.append(command).append(";type").append(type).append("控制打开").append(slotId).append("柜门"); |
| | | String mes = mesBuilder.toString(); |
| | | |
| | | Charulog.logOperation(mes); |
| | | if (lunxun.DEBUG_ENABLED) { |
| | | SystemDebugDialog.appendAsciiData(mes); |
| | | } |
| | | |
| | | return sendResult; |
| | | } finally { |
| | | // 确保恢复查询指令 |
| | | lunxun.setSendChaxunzhiling(true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 打开全部卡槽的公用静态方法 |
| | | * @param type 操作类型:1-服务器发卡,2-管理员发卡 |
| | | */ |
| | | public static void openAllSlots(int type) { |
| | | lunxun.setSendChaxunzhiling(false);//暂停查询指令 |
| | | |
| | | String workerKey = "openAllSlots_" + System.currentTimeMillis(); |
| | | |
| | | // 使用SwingWorker在后台执行,避免阻塞UI |
| | | SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() { |
| | | @Override |
| | | protected Void doInBackground() throws Exception { |
| | | // 遍历所有卡槽(1-60) |
| | | for (int slotId = 1; slotId <= 60 && !isCancelled(); slotId++) { |
| | | try { |
| | | // 生成开门指令 |
| | | String command = OpenDoor.openOneDoor(slotId, type); |
| | | |
| | | // 发送串口指令 |
| | | boolean sent = Sendmsg.sendMessage(command); |
| | | |
| | | if (!sent) { |
| | | Errlog.logOperation("发送指令到卡槽 " + slotId + " 失败"); |
| | | } |
| | | |
| | | // 间隔100ms,但检查是否被取消 |
| | | Thread.sleep(100); |
| | | |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | break; // 被中断时退出循环 |
| | | } catch (Exception e) { |
| | | Errlog.logOperation("处理卡槽 " + slotId + " 时发生错误: " + e.getMessage()); |
| | | // 继续处理下一个卡槽,不中断循环 |
| | | } |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | @Override |
| | | protected void done() { |
| | | try { |
| | | // 清理worker引用 |
| | | ACTIVE_WORKERS.remove(workerKey); |
| | | |
| | | // 可选:完成后可以添加回调处理 |
| | | if (!isCancelled()) { |
| | | StringBuilder messageBuilder = STRING_BUILDER_CACHE.get(); |
| | | messageBuilder.setLength(0); |
| | | |
| | | String types = "管理员"; |
| | | if(type == 1) { |
| | | types = "服务器指令"; |
| | | } |
| | | messageBuilder.append(types).append("已将全部卡槽已经打开请取卡"); |
| | | String message = messageBuilder.toString(); |
| | | |
| | | Dingshidialog.showTimedDialog(null, 5, message); |
| | | Charulog.logOperation(message); |
| | | } |
| | | } finally { |
| | | // 确保恢复查询指令 |
| | | lunxun.setSendChaxunzhiling(true); |
| | | } |
| | | } |
| | | }; |
| | | |
| | | // 记录worker便于管理 |
| | | ACTIVE_WORKERS.put(workerKey, worker); |
| | | worker.execute(); |
| | | } |
| | | |
| | | /** |
| | | * 取消所有正在执行的任务 |
| | | */ |
| | | public static void cancelAllTasks() { |
| | | ACTIVE_WORKERS.forEach((key, worker) -> { |
| | | if (!worker.isDone()) { |
| | | worker.cancel(true); |
| | | } |
| | | }); |
| | | ACTIVE_WORKERS.clear(); |
| | | } |
| | | |
| | | /** |
| | | * 设置串口服务实例 |
| | |
| | | */ |
| | | public static void setSerialService(SerialPortService service, boolean open) { |
| | | serialService = service; |
| | | isPortOpen = open; |
| | | isPortOpen.set(open); |
| | | } |
| | | |
| | | /** |
| | |
| | | * 发送消息到串口(带重试机制) |
| | | */ |
| | | public static boolean sendMessage(String message) { |
| | | if (!isPortOpen || serialService == null) { |
| | | System.err.println("[" + getCurrentTime() + "] 串口未打开,无法发送数据"); |
| | | if (!isPortOpen.get() || serialService == null) { |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 串口未打开,无法发送数据"); |
| | | return false; |
| | | } |
| | | |
| | | if (message == null || message.trim().isEmpty()) { |
| | | System.err.println("[" + getCurrentTime() + "] 发送数据为空"); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 发送数据为空"); |
| | | return false; |
| | | } |
| | | |
| | |
| | | try { |
| | | byte[] data = hexStringToByteArray(text); |
| | | if (data == null) { |
| | | System.err.println("[" + getCurrentTime() + "] HEX转换失败,数据: " + text); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] HEX转换失败,数据: " + text); |
| | | return false; |
| | | } |
| | | |
| | |
| | | } else { |
| | | retryCount++; |
| | | if (retryCount <= MAX_RETRY) { |
| | | System.err.println("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")"); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 发送失败,正在重试 (" + retryCount + "/" + MAX_RETRY + ")"); |
| | | try { |
| | | Thread.sleep(50); // 重试前等待 |
| | | } catch (InterruptedException e) { |
| | |
| | | break; |
| | | } |
| | | } else { |
| | | System.err.println("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase()); |
| | | System.err.println("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen + ", 服务: " + (serialService != null)); |
| | | if (serialService != null) { |
| | | System.err.println("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen()); |
| | | if (DEBUG_MODE) { |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 串口发送失败,指令: " + text.toUpperCase()); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 串口状态 - 打开: " + isPortOpen.get() + ", 服务: " + (serialService != null)); |
| | | if (serialService != null) { |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 串口服务状态 - 是否打开: " + serialService.isOpen()); |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | System.err.println("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase()); |
| | | e.printStackTrace(); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 发送异常,指令: " + text.toUpperCase()); |
| | | if (DEBUG_MODE) { |
| | | e.printStackTrace(); |
| | | } |
| | | return false; |
| | | } |
| | | } |
| | |
| | | * @return 串口打开状态 |
| | | */ |
| | | public static boolean isPortOpen() { |
| | | boolean open = isPortOpen && serialService != null; |
| | | boolean open = isPortOpen.get() && serialService != null; |
| | | if (!open && DEBUG_MODE) { |
| | | System.err.println("[" + getCurrentTime() + "] 串口状态检查: 未打开"); |
| | | Errlog.logOperation("[" + getCurrentTime() + "] 串口状态检查: 未打开"); |
| | | } |
| | | return open; |
| | | } |
| | |
| | | return ""; |
| | | } |
| | | |
| | | StringBuilder sb = new StringBuilder(); |
| | | StringBuilder sb = STRING_BUILDER_CACHE.get(); |
| | | sb.setLength(0); |
| | | for (byte b : bytes) { |
| | | sb.append(String.format("%02x", b)); |
| | | } |
| | |
| | | * @return 时间字符串 |
| | | */ |
| | | private static String getCurrentTime() { |
| | | return timeFormat.format(new Date()); |
| | | return TIME_FORMATTER.get().format(new Date()); |
| | | } |
| | | |
| | | /** |
| | |
| | | DEBUG_MODE = debug; |
| | | System.out.println("[" + getCurrentTime() + "] Sendmsg调试模式: " + (debug ? "启用" : "禁用")); |
| | | } |
| | | |
| | | /** |
| | | * 清理资源,防止内存泄漏 |
| | | */ |
| | | public static void cleanup() { |
| | | cancelAllTasks(); |
| | | |
| | | // 清理ThreadLocal资源 |
| | | TIME_FORMATTER.remove(); |
| | | STRING_BUILDER_CACHE.remove(); |
| | | |
| | | if (DEBUG_MODE) { |
| | | System.out.println("[" + getCurrentTime() + "] Sendmsg资源清理完成"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 获取活跃任务数量 |
| | | */ |
| | | public static int getActiveTaskCount() { |
| | | return ACTIVE_WORKERS.size(); |
| | | } |
| | | } |