| | |
| | | import java.util.concurrent.CopyOnWriteArrayList; |
| | | import java.util.concurrent.atomic.AtomicInteger; |
| | | import java.util.concurrent.atomic.AtomicReference; |
| | | import java.util.function.Consumer; |
| | | // import java.util.function.Consumer; |
| | | |
| | | /** |
| | | * 串口实时数据调度中心。 |
| | |
| | | * GNGGA 数据的内置解析支持,复用 UDP 处理逻辑。 |
| | | */ |
| | | public final class dellmessage { |
| | | private static final CopyOnWriteArrayList<Consumer<byte[]>> RAW_CONSUMERS = new CopyOnWriteArrayList<>(); |
| | | private static final CopyOnWriteArrayList<Consumer<String>> LINE_CONSUMERS = new CopyOnWriteArrayList<>(); |
| | | private static final CopyOnWriteArrayList<DataListener<byte[]>> RAW_CONSUMERS = new CopyOnWriteArrayList<>(); |
| | | private static final CopyOnWriteArrayList<DataListener<String>> LINE_CONSUMERS = new CopyOnWriteArrayList<>(); |
| | | private static final StringBuilder LINE_BUFFER = new StringBuilder(512); |
| | | private static final AtomicInteger LINE_COUNTER = new AtomicInteger(0); |
| | | private static final AtomicReference<String> LAST_LINE = new AtomicReference<>(""); |
| | |
| | | * |
| | | * @param consumer 接收完整数据帧的监听器 |
| | | */ |
| | | public static void registerRawListener(Consumer<byte[]> consumer) { |
| | | public static void registerRawListener(DataListener<byte[]> consumer) { |
| | | // 用法:在需要直接处理原始串口字节流的模块启动时调用,传入回调处理数据帧。 |
| | | if (consumer != null) { |
| | | RAW_CONSUMERS.addIfAbsent(consumer); |
| | |
| | | /** |
| | | * 注销原始字节监听器。 |
| | | */ |
| | | public static void unregisterRawListener(Consumer<byte[]> consumer) { |
| | | public static void unregisterRawListener(DataListener<byte[]> consumer) { |
| | | // 用法:模块销毁或不再需要接收原始数据时调用,避免内存泄漏。 |
| | | if (consumer != null) { |
| | | RAW_CONSUMERS.remove(consumer); |
| | |
| | | * <p> |
| | | * 每一条经由换行符截断的完整文本行将触发一次回调。 |
| | | */ |
| | | public static void registerLineListener(Consumer<String> consumer) { |
| | | public static void registerLineListener(DataListener<String> consumer) { |
| | | // 用法:需要按行读取串口文本(如 NMEA 报文)时调用,回调拿到完整文本行。 |
| | | if (consumer != null) { |
| | | LINE_CONSUMERS.addIfAbsent(consumer); |
| | |
| | | /** |
| | | * 注销文本行监听器。 |
| | | */ |
| | | public static void unregisterLineListener(Consumer<String> consumer) { |
| | | public static void unregisterLineListener(DataListener<String> consumer) { |
| | | // 用法:对应 registerLineListener 的反注册操作,通常在窗口关闭或服务停止时调用。 |
| | | if (consumer != null) { |
| | | LINE_CONSUMERS.remove(consumer); |
| | |
| | | } |
| | | |
| | | private static void notifyRawConsumers(byte[] data) { |
| | | for (Consumer<byte[]> consumer : RAW_CONSUMERS) { |
| | | for (DataListener<byte[]> consumer : RAW_CONSUMERS) { |
| | | try { |
| | | consumer.accept(data); |
| | | } catch (Exception ex) { |
| | |
| | | } |
| | | |
| | | LAST_LINE.set(line); |
| | | LINE_COUNTER.updateAndGet(count -> count >= 10000 ? 1 : count + 1); |
| | | // LINE_COUNTER.updateAndGet(count -> count >= 10000 ? 1 : count + 1); |
| | | int current, next; |
| | | do { |
| | | current = LINE_COUNTER.get(); |
| | | next = (current >= 10000) ? 1 : current + 1; |
| | | } while (!LINE_COUNTER.compareAndSet(current, next)); |
| | | |
| | | for (Consumer<String> consumer : LINE_CONSUMERS) { |
| | | for (DataListener<String> consumer : LINE_CONSUMERS) { |
| | | try { |
| | | consumer.accept(line); |
| | | } catch (Exception ex) { |