improving mock voltage slider response time by aggregating commands
This commit is contained in:
parent
8f10e85d03
commit
b023353457
|
@ -14,7 +14,7 @@ import java.util.concurrent.LinkedBlockingQueue;
|
||||||
*
|
*
|
||||||
* <p/>
|
* <p/>
|
||||||
* Date: 1/7/13
|
* Date: 1/7/13
|
||||||
* (c) Andrey Belomutskiy
|
* (c) Andrey Belomutskiy 2013-2019
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
public class CommandQueue {
|
public class CommandQueue {
|
||||||
|
@ -32,7 +32,7 @@ public class CommandQueue {
|
||||||
private Set<String> pendingConfirmations = Collections.synchronizedSet(new HashSet<String>());
|
private Set<String> pendingConfirmations = Collections.synchronizedSet(new HashSet<String>());
|
||||||
|
|
||||||
private static final CommandQueue instance = new CommandQueue();
|
private static final CommandQueue instance = new CommandQueue();
|
||||||
private final BlockingQueue<MethodInvocation> pendingCommands = new LinkedBlockingQueue<>();
|
private final BlockingQueue<IMethodInvocation> pendingCommands = new LinkedBlockingQueue<>();
|
||||||
private final List<CommandQueueListener> commandListeners = new ArrayList<>();
|
private final List<CommandQueueListener> commandListeners = new ArrayList<>();
|
||||||
|
|
||||||
private final Runnable runnable = new Runnable() {
|
private final Runnable runnable = new Runnable() {
|
||||||
|
@ -74,7 +74,7 @@ public class CommandQueue {
|
||||||
* here we block in case there is no command to send
|
* here we block in case there is no command to send
|
||||||
*/
|
*/
|
||||||
@NotNull
|
@NotNull
|
||||||
final MethodInvocation command = pendingCommands.take();
|
final IMethodInvocation command = pendingCommands.take();
|
||||||
// got a command? let's send it!
|
// got a command? let's send it!
|
||||||
sendCommand(command);
|
sendCommand(command);
|
||||||
}
|
}
|
||||||
|
@ -82,14 +82,14 @@ public class CommandQueue {
|
||||||
/**
|
/**
|
||||||
* this method keeps retrying till a confirmation is received
|
* this method keeps retrying till a confirmation is received
|
||||||
*/
|
*/
|
||||||
private void sendCommand(final MethodInvocation commandRequest) throws InterruptedException {
|
private void sendCommand(final IMethodInvocation commandRequest) throws InterruptedException {
|
||||||
int counter = 0;
|
int counter = 0;
|
||||||
String command = commandRequest.getCommand();
|
String command = commandRequest.getCommand();
|
||||||
|
|
||||||
while (!pendingConfirmations.contains(command)) {
|
while (!pendingConfirmations.contains(command)) {
|
||||||
counter++;
|
counter++;
|
||||||
// FileLog.MAIN.logLine("templog sending " + command + " " + System.currentTimeMillis() + " " + new Date());
|
// FileLog.MAIN.logLine("templog sending " + command + " " + System.currentTimeMillis() + " " + new Date());
|
||||||
LinkManager.send(command, commandRequest.fireEvent);
|
LinkManager.send(command, commandRequest.isFireEvent());
|
||||||
long now = System.currentTimeMillis();
|
long now = System.currentTimeMillis();
|
||||||
synchronized (lock) {
|
synchronized (lock) {
|
||||||
lock.wait(commandRequest.getTimeout());
|
lock.wait(commandRequest.getTimeout());
|
||||||
|
@ -106,7 +106,7 @@ public class CommandQueue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (pendingConfirmations.contains(command)) {
|
if (pendingConfirmations.contains(command)) {
|
||||||
commandRequest.listener.onCommandConfirmation();
|
commandRequest.getListener().onCommandConfirmation();
|
||||||
pendingConfirmations.remove(command);
|
pendingConfirmations.remove(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,7 +178,13 @@ public class CommandQueue {
|
||||||
pendingCommands.add(new MethodInvocation(command, timeoutMs, listener, fireEvent));
|
pendingCommands.add(new MethodInvocation(command, timeoutMs, listener, fireEvent));
|
||||||
}
|
}
|
||||||
|
|
||||||
static class MethodInvocation {
|
public void addIfNotPresent(IMethodInvocation commandSender) {
|
||||||
|
// technically this should be a critical locked section but for our use-case we do not care
|
||||||
|
if (!pendingCommands.contains(commandSender))
|
||||||
|
pendingCommands.add(commandSender);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class MethodInvocation implements IMethodInvocation {
|
||||||
private final String command;
|
private final String command;
|
||||||
private final int timeoutMs;
|
private final int timeoutMs;
|
||||||
private final InvocationConfirmationListener listener;
|
private final InvocationConfirmationListener listener;
|
||||||
|
@ -191,14 +197,26 @@ public class CommandQueue {
|
||||||
this.fireEvent = fireEvent;
|
this.fireEvent = fireEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getCommand() {
|
public String getCommand() {
|
||||||
return command;
|
return command;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public int getTimeout() {
|
public int getTimeout() {
|
||||||
return timeoutMs;
|
return timeoutMs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InvocationConfirmationListener getListener() {
|
||||||
|
return listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFireEvent() {
|
||||||
|
return fireEvent;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "MethodInvocation{" +
|
return "MethodInvocation{" +
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
package com.rusefi.io;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* (c) Andrey Belomutskiy 2013-2019
|
||||||
|
*/
|
||||||
|
public interface IMethodInvocation {
|
||||||
|
String getCommand();
|
||||||
|
|
||||||
|
int getTimeout();
|
||||||
|
|
||||||
|
InvocationConfirmationListener getListener();
|
||||||
|
|
||||||
|
boolean isFireEvent();
|
||||||
|
}
|
|
@ -3,14 +3,14 @@ package com.rusefi.ui.widgets;
|
||||||
import com.rusefi.config.generated.Fields;
|
import com.rusefi.config.generated.Fields;
|
||||||
import com.rusefi.core.Sensor;
|
import com.rusefi.core.Sensor;
|
||||||
import com.rusefi.io.CommandQueue;
|
import com.rusefi.io.CommandQueue;
|
||||||
|
import com.rusefi.io.IMethodInvocation;
|
||||||
|
import com.rusefi.io.InvocationConfirmationListener;
|
||||||
import com.rusefi.io.LinkManager;
|
import com.rusefi.io.LinkManager;
|
||||||
import com.rusefi.ui.GaugesPanel;
|
import com.rusefi.ui.GaugesPanel;
|
||||||
import com.rusefi.ui.storage.Node;
|
import com.rusefi.ui.storage.Node;
|
||||||
import com.rusefi.ui.util.UiUtils;
|
import com.rusefi.ui.util.UiUtils;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import javax.swing.event.ChangeEvent;
|
|
||||||
import javax.swing.event.ChangeListener;
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.awt.event.WindowAdapter;
|
import java.awt.event.WindowAdapter;
|
||||||
|
@ -20,9 +20,10 @@ import java.text.Format;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
|
import java.util.concurrent.atomic.AtomicReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* (c) Andrey Belomutskiy
|
* (c) Andrey Belomutskiy 2013-2019
|
||||||
* 11/2/14
|
* 11/2/14
|
||||||
*/
|
*/
|
||||||
public class DetachedSensor {
|
public class DetachedSensor {
|
||||||
|
@ -82,12 +83,7 @@ public class DetachedSensor {
|
||||||
}
|
}
|
||||||
|
|
||||||
void create() {
|
void create() {
|
||||||
SensorGauge.GaugeChangeListener listener = new SensorGauge.GaugeChangeListener() {
|
SensorGauge.GaugeChangeListener listener = this::onChange;
|
||||||
@Override
|
|
||||||
public void onSensorChange(Sensor sensor) {
|
|
||||||
onChange(sensor);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
content.add(SensorGauge.createGauge(sensor, listener, null), BorderLayout.CENTER);
|
content.add(SensorGauge.createGauge(sensor, listener, null), BorderLayout.CENTER);
|
||||||
content.add(mockControlPanel, BorderLayout.SOUTH);
|
content.add(mockControlPanel, BorderLayout.SOUTH);
|
||||||
|
|
||||||
|
@ -123,8 +119,6 @@ public class DetachedSensor {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Component createMockVoltageSlider(final Sensor sensor) {
|
public static Component createMockVoltageSlider(final Sensor sensor) {
|
||||||
/**
|
|
||||||
*/
|
|
||||||
final JSlider slider = new JSlider(0, _5_VOLTS_WITH_DECIMAL);
|
final JSlider slider = new JSlider(0, _5_VOLTS_WITH_DECIMAL);
|
||||||
slider.setLabelTable(SLIDER_LABELS);
|
slider.setLabelTable(SLIDER_LABELS);
|
||||||
slider.setPaintLabels(true);
|
slider.setPaintLabels(true);
|
||||||
|
@ -132,12 +126,41 @@ public class DetachedSensor {
|
||||||
slider.setMajorTickSpacing(10);
|
slider.setMajorTickSpacing(10);
|
||||||
slider.setMinorTickSpacing(5);
|
slider.setMinorTickSpacing(5);
|
||||||
|
|
||||||
slider.addChangeListener(new ChangeListener() {
|
AtomicReference<Double> pendingValue = new AtomicReference<>();
|
||||||
|
|
||||||
|
IMethodInvocation commandSender = new IMethodInvocation() {
|
||||||
@Override
|
@Override
|
||||||
public void stateChanged(ChangeEvent e) {
|
public String getCommand() {
|
||||||
double value = slider.getValue() / 10.0;
|
return "set mock_" + sensor.name().toLowerCase() + "_voltage " + pendingValue.get();
|
||||||
CommandQueue.getInstance().write("set mock_" + sensor.name().toLowerCase() + "_voltage " + value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTimeout() {
|
||||||
|
return CommandQueue.DEFAULT_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InvocationConfirmationListener getListener() {
|
||||||
|
return InvocationConfirmationListener.VOID;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFireEvent() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
slider.addChangeListener(e -> {
|
||||||
|
double value = slider.getValue() / 10.0;
|
||||||
|
CommandQueue commandQueue = CommandQueue.getInstance();
|
||||||
|
pendingValue.set(value);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User might be changing slider faster than commands are being send
|
||||||
|
* We only add commandSender into the queue only if not already pending in order to only send one command with latest requested value and not a sequence of commands.
|
||||||
|
*/
|
||||||
|
commandQueue.addIfNotPresent(commandSender);
|
||||||
});
|
});
|
||||||
|
|
||||||
return slider;
|
return slider;
|
||||||
|
|
Loading…
Reference in New Issue