From a92ac0754850b2842527bd0dfec3f7534db11cc3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sun, 13 Feb 2022 18:28:00 +0100 Subject: [PATCH] Pass a scan reason for scheduling bus scan, so we can immediately retry when errors may be fixed, but avoid ping-pong while errors persist. --- .../cil/oc2/api/bus/DeviceBusController.java | 24 ++++++++++++++--- .../common/bus/CommonDeviceBusController.java | 27 ++++++++++++------- 2 files changed, 38 insertions(+), 13 deletions(-) diff --git a/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java b/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java index 54d625e4..d8ab8126 100644 --- a/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java +++ b/src/main/java/li/cil/oc2/api/bus/DeviceBusController.java @@ -31,17 +31,33 @@ import java.util.UUID; * @see DeviceBusElement */ public interface DeviceBusController { + /** + * Reason for a bus scan. Used to determine whether to immediately perform the scan or no, for example. + */ + enum ScanReason { + BUS_CHANGE, + BUS_ERROR, + } + /** * Schedules a scan. *

- * This will immediately invalidate the current bus, i.e. all {@link DeviceBusElement}s - * will be removed from the controller and {@link #getDevices()} will return an empty - * list after this call. + * Multiple sequential calls to this method do nothing, the actual scan will be performed + * in the next update. + * + * @param reason the reason for the bus scan. + */ + void scheduleBusScan(ScanReason reason); + + /** + * Schedules a scan due to a bus configuration change. *

* Multiple sequential calls to this method do nothing, the actual scan will be performed * in the next update. */ - void scheduleBusScan(); + default void scheduleBusScan() { + scheduleBusScan(ScanReason.BUS_CHANGE); + } /** * Forces a device map rebuild. diff --git a/src/main/java/li/cil/oc2/common/bus/CommonDeviceBusController.java b/src/main/java/li/cil/oc2/common/bus/CommonDeviceBusController.java index 7187638e..f1590fd3 100644 --- a/src/main/java/li/cil/oc2/common/bus/CommonDeviceBusController.java +++ b/src/main/java/li/cil/oc2/common/bus/CommonDeviceBusController.java @@ -66,8 +66,10 @@ public class CommonDeviceBusController implements DeviceBusController { public void dispose() { for (final DeviceBusElement element : elements) { element.removeController(this); + + // Let other controllers on the bus know we're gone, so they can quickly recover. for (final DeviceBusController controller : element.getControllers()) { - controller.scheduleBusScan(); + controller.scheduleBusScan(ScanReason.BUS_CHANGE); } } @@ -83,13 +85,15 @@ public class CommonDeviceBusController implements DeviceBusController { } @Override - public void scheduleBusScan() { - // For multiple controllers, avoid ping-ponging immediate scans when controllers - // detect each other during their scans. - if (state != BusState.MULTIPLE_CONTROLLERS) { - scanDelay = 0; // scan as soon as possible - state = BusState.SCAN_PENDING; + public void scheduleBusScan(final ScanReason reason) { + // For notification of a bus error, we just keep our old state and delay, if we have one. + // Avoids ping-ponging error states causing scans every tick. + if (reason == ScanReason.BUS_ERROR && state.ordinal() < BusState.READY.ordinal()) { + return; } + + scanDelay = 0; // scan as soon as possible + state = BusState.SCAN_PENDING; } @Override @@ -172,7 +176,7 @@ public class CommonDeviceBusController implements DeviceBusController { // Rescan if any bus element gets invalidated. Don't have bus elements keep this instance alive, // only notify us on change if we still exist. LazyOptionalUtils.addWeakListener(optionals.get(element), this, - (controller, ignored) -> controller.scheduleBusScan()); + (controller, ignored) -> controller.scheduleBusScan(ScanReason.BUS_CHANGE)); } scanDevices(); @@ -273,6 +277,11 @@ public class CommonDeviceBusController implements DeviceBusController { for (final DeviceBusElement removedElement : removedElements) { removedElement.removeController(this); + + // Let other controllers on the bus know we're gone, so they can quickly recover. + for (final DeviceBusController controller : removedElement.getControllers()) { + controller.scheduleBusScan(ScanReason.BUS_CHANGE); + } } final HashSet addedElements = new HashSet<>(newElements); @@ -302,7 +311,7 @@ public class CommonDeviceBusController implements DeviceBusController { // trigger a scan for those controllers, too, so they may enter error state. for (final DeviceBusController controller : controllers) { - controller.scheduleBusScan(); + controller.scheduleBusScan(ScanReason.BUS_ERROR); } state = BusState.MULTIPLE_CONTROLLERS;