Initial commit
Some checks failed
Gradle Build / build (push) Has been cancelled

This commit is contained in:
CaiXiang
2024-11-30 18:36:13 +08:00
commit aa56926258
2134 changed files with 232943 additions and 0 deletions

View File

@@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.opentcs.customizations.controlcenter.ControlCenterInjectionModule;
/**
* Loopback adapter-specific Gucie configuration for the Kernel Control Center.
*/
public class LoopbackPeripheralControlCenterModule
extends
ControlCenterInjectionModule {
/**
* Creates a new instance.
*/
public LoopbackPeripheralControlCenterModule() {
}
@Override
protected void configure() {
install(
new FactoryModuleBuilder().build(LoopbackPeripheralAdapterPanelComponentsFactory.class)
);
peripheralCommAdapterPanelFactoryBinder()
.addBinding().to(LoopbackPeripheralCommAdapterPanelFactory.class);
}
}

View File

@@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import org.opentcs.customizations.kernel.KernelInjectionModule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Loopback adapter-specific Gucie configuration for the Kernel.
*/
public class LoopbackPeripheralKernelModule
extends
KernelInjectionModule {
/**
* This class's logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(LoopbackPeripheralKernelModule.class);
/**
* Creates a new instance.
*/
public LoopbackPeripheralKernelModule() {
}
@Override
protected void configure() {
VirtualPeripheralConfiguration configuration
= getConfigBindingProvider().get(
VirtualPeripheralConfiguration.PREFIX,
VirtualPeripheralConfiguration.class
);
if (!configuration.enable()) {
LOG.info("Peripheral loopback driver disabled by configuration.");
return;
}
bind(VirtualPeripheralConfiguration.class)
.toInstance(configuration);
install(new FactoryModuleBuilder().build(LoopbackPeripheralAdapterComponentsFactory.class));
// tag::documentation_createCommAdapterModule[]
peripheralCommAdaptersBinder().addBinding().to(LoopbackPeripheralCommAdapterFactory.class);
// end::documentation_createCommAdapterModule[]
}
}

View File

@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: MIT
org.opentcs.commadapter.peripheral.loopback.LoopbackPeripheralControlCenterModule

View File

@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: MIT
org.opentcs.commadapter.peripheral.loopback.LoopbackPeripheralKernelModule

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
/**
* Defines constants regarding internationalization.
*/
public interface I18nLoopbackPeripheralCommAdapter {
/**
* The path to the project's resource bundle.
*/
String BUNDLE_PATH = "i18n/org/opentcs/commadapter/peripheral/loopback/Bundle";
}

View File

@@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
/**
*/
public interface LocationProperties {
/**
* The key of the location property indicating that the location represents a peripheral device
* and that it should be attached to the loopback peripheral communication adapter.
*/
String PROPKEY_LOOPBACK_PERIPHERAL = "tcs:loopbackPeripheral";
}

View File

@@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import org.opentcs.data.model.Location;
import org.opentcs.data.model.TCSResourceReference;
/**
* A factory for various loopback specific instances.
*/
public interface LoopbackPeripheralAdapterComponentsFactory {
/**
* Creates a new loopback communication adapter for the given location.
*
* @param location The location.
* @return A loopback communication adapter instance.
*/
LoopbackPeripheralCommAdapter createLoopbackCommAdapter(TCSResourceReference<Location> location);
}

View File

@@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
/**
* A factory for creating various comm adapter panel-specific instances.
*/
public interface LoopbackPeripheralAdapterPanelComponentsFactory {
/**
* Creates a {@link LoopbackPeripheralCommAdapterPanel} representing the given process model's
* content.
*
* @param processModel The process model to represent.
* @return The comm adapter panel.
*/
LoopbackPeripheralCommAdapterPanel createPanel(LoopbackPeripheralProcessModel processModel);
}

View File

@@ -0,0 +1,230 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import static java.util.Objects.requireNonNull;
import static org.opentcs.util.Assertions.checkState;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.time.Duration;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Future;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.customizations.kernel.KernelExecutor;
import org.opentcs.data.model.Location;
import org.opentcs.data.model.PeripheralInformation;
import org.opentcs.data.model.TCSResourceReference;
import org.opentcs.data.peripherals.PeripheralJob;
import org.opentcs.drivers.peripherals.BasicPeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralAdapterCommand;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralJobCallback;
import org.opentcs.drivers.peripherals.PeripheralProcessModel;
import org.opentcs.drivers.peripherals.management.PeripheralProcessModelEvent;
import org.opentcs.util.ExplainedBoolean;
import org.opentcs.util.event.EventHandler;
/**
* A {@link PeripheralCommAdapter} implementation that is doing nothing.
*/
public class LoopbackPeripheralCommAdapter
extends
BasicPeripheralCommAdapter {
/**
* The time it takes for loopback peripherals to process a job.
*/
private static final Duration JOB_PROCESSING_DURATION = Duration.ofSeconds(10);
/**
* The kernel's executor.
*/
private final ScheduledExecutorService kernelExecutor;
/**
* The queue of tasks to be executed to simulate the processing of jobs.
* This queue may contain at most one item at any time.
*/
private final Queue<Runnable> jobTaskQueue = new ArrayDeque<>();
/**
* A future for the current job task's execution.
* Indicates whehter the current job task has been executed or whether it is still to be executed.
*/
private Future<?> currentJobFuture;
/**
* Whether the execution of jobs should fail.
*/
private boolean failJobs;
/**
* Creates a new instance.
*
* @param location The reference to the location this adapter is attached to.
* @param eventHandler The handler used to send events to.
* @param kernelExecutor The kernel's executor.
*/
@Inject
public LoopbackPeripheralCommAdapter(
@Assisted
TCSResourceReference<Location> location,
@ApplicationEventBus
EventHandler eventHandler,
@KernelExecutor
ScheduledExecutorService kernelExecutor
) {
super(new LoopbackPeripheralProcessModel(location), eventHandler);
this.kernelExecutor = requireNonNull(kernelExecutor, "kernelExecutor");
}
@Override
public void initialize() {
if (isInitialized()) {
return;
}
super.initialize();
setProcessModel(getProcessModel().withState(PeripheralInformation.State.IDLE));
sendProcessModelChangedEvent(PeripheralProcessModel.Attribute.STATE);
}
@Override
public LoopbackPeripheralProcessModel getProcessModel() {
return (LoopbackPeripheralProcessModel) super.getProcessModel();
}
@Override
public ExplainedBoolean canProcess(PeripheralJob job) {
if (!isEnabled()) {
return new ExplainedBoolean(false, "Comm adapter not enabled.");
}
else if (hasJobWaitingToBeProcessed()) {
return new ExplainedBoolean(false, "Busy processing another job.");
}
return new ExplainedBoolean(true, "");
}
@Override
public void process(PeripheralJob job, PeripheralJobCallback callback) {
ExplainedBoolean canProcess = canProcess(job);
checkState(
canProcess.getValue(),
"%s: Can't process job: %s",
getProcessModel().getLocation().getName(),
canProcess.getReason()
);
jobTaskQueue.add(() -> {
if (failJobs) {
callback.peripheralJobFailed(job.getReference());
}
else {
callback.peripheralJobFinished(job.getReference());
}
setProcessModel(getProcessModel().withState(PeripheralInformation.State.IDLE));
sendProcessModelChangedEvent(PeripheralProcessModel.Attribute.STATE);
});
setProcessModel(getProcessModel().withState(PeripheralInformation.State.EXECUTING));
sendProcessModelChangedEvent(PeripheralProcessModel.Attribute.STATE);
if (!getProcessModel().isManualModeEnabled()) {
currentJobFuture = kernelExecutor.schedule(
jobTaskQueue.poll(),
JOB_PROCESSING_DURATION.getSeconds(),
TimeUnit.SECONDS
);
}
}
@Override
public void abortJob() {
jobTaskQueue.clear();
if (currentJobFuture != null) {
currentJobFuture.cancel(false);
}
setProcessModel(getProcessModel().withState(PeripheralInformation.State.IDLE));
sendProcessModelChangedEvent(PeripheralProcessModel.Attribute.STATE);
}
@Override
public void execute(PeripheralAdapterCommand command) {
command.execute(this);
}
@Override
protected void connectPeripheral() {
}
@Override
protected void disconnectPeripheral() {
}
public void enableManualMode(boolean enabled) {
kernelExecutor.submit(() -> {
LoopbackPeripheralProcessModel oldProcessModel = getProcessModel();
setProcessModel(getProcessModel().withManualModeEnabled(enabled));
if (oldProcessModel.isManualModeEnabled() && !getProcessModel().isManualModeEnabled()) {
// Job processing mode changed to "automatic". If there's a task that has not yet been
// processed while the processing mode was set to "manual", make sure the task is executed
// and schedule it for execution on the kernel executor.
if (!jobTaskQueue.isEmpty()) {
currentJobFuture = kernelExecutor.submit(jobTaskQueue.poll());
}
}
sendProcessModelChangedEvent(LoopbackPeripheralProcessModel.Attribute.MANUAL_MODE_ENABLED);
});
}
public void updateState(PeripheralInformation.State state) {
kernelExecutor.submit(() -> {
setProcessModel(getProcessModel().withState(state));
sendProcessModelChangedEvent(PeripheralProcessModel.Attribute.STATE);
});
}
public void triggerJobProcessing(boolean failJob) {
if (!getProcessModel().isManualModeEnabled()) {
return;
}
if (jobTaskQueue.isEmpty() || !isCurrentJobFutureDone()) {
// There's no job to be processed or we are not yet done processing the current one.
return;
}
currentJobFuture = kernelExecutor.submit(() -> {
failJobs = failJob;
jobTaskQueue.poll().run();
failJobs = false;
});
}
private boolean hasJobWaitingToBeProcessed() {
return !jobTaskQueue.isEmpty() || !isCurrentJobFutureDone();
}
private boolean isCurrentJobFutureDone() {
if (currentJobFuture == null) {
return true;
}
return currentJobFuture.isDone();
}
private void sendProcessModelChangedEvent(
LoopbackPeripheralProcessModel.Attribute attributeChanged
) {
getEventHandler().onEvent(
new PeripheralProcessModelEvent(
getProcessModel().getLocation(),
attributeChanged.name(),
getProcessModel()
)
);
}
}

View File

@@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import static org.opentcs.commadapter.peripheral.loopback.I18nLoopbackPeripheralCommAdapter.BUNDLE_PATH;
import java.util.ResourceBundle;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
/**
* A {@link PeripheralCommAdapterDescription} for no comm adapter.
*/
public class LoopbackPeripheralCommAdapterDescription
extends
PeripheralCommAdapterDescription {
/**
* Creates a new instance.
*/
public LoopbackPeripheralCommAdapterDescription() {
}
@Override
public String getDescription() {
return ResourceBundle.getBundle(BUNDLE_PATH)
.getString("loopbackPeripheralCommAdapterDescription.description");
}
}

View File

@@ -0,0 +1,73 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import static java.util.Objects.requireNonNull;
import jakarta.inject.Inject;
import org.opentcs.data.model.Location;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterFactory;
/**
* A factory for loopback communication adapters (virtual peripherals).
*/
public class LoopbackPeripheralCommAdapterFactory
implements
PeripheralCommAdapterFactory {
/**
* The adapter components factory.
*/
private final LoopbackPeripheralAdapterComponentsFactory componentsFactory;
/**
* Indicates whether this component is initialized or not.
*/
private boolean initialized;
@Inject
public LoopbackPeripheralCommAdapterFactory(
LoopbackPeripheralAdapterComponentsFactory componentsFactory
) {
this.componentsFactory = requireNonNull(componentsFactory, "componentsFactory");
}
@Override
public void initialize() {
if (isInitialized()) {
return;
}
initialized = true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (!isInitialized()) {
return;
}
initialized = false;
}
@Override
public PeripheralCommAdapterDescription getDescription() {
return new LoopbackPeripheralCommAdapterDescription();
}
@Override
public boolean providesAdapterFor(Location location) {
requireNonNull(location, "location");
return location.getProperties().containsKey(LocationProperties.PROPKEY_LOOPBACK_PERIPHERAL);
}
@Override
public PeripheralCommAdapter getAdapterFor(Location location) {
requireNonNull(location, "location");
return componentsFactory.createLoopbackCommAdapter(location.getReference());
}
}

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AccessibilityProperties>
<Property name="AccessibleContext.accessibleName" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.accessibleName" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</AccessibilityProperties>
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0">
<Component id="statePanel" pref="194" max="32767" attributes="0"/>
<Component id="jobProcessingPanel" max="32767" attributes="0"/>
</Group>
<EmptySpace pref="170" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="statePanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jobProcessingPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="165" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Container class="javax.swing.JPanel" name="statePanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Current state">
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.panel_state.border.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
<Property name="name" type="java.lang.String" value="statePanel" noResource="true"/>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JLabel" name="stateLabel">
<Properties>
<Property name="horizontalAlignment" type="int" value="11"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.label_state.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
</Properties>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JComboBox" name="stateComboBox">
<Properties>
<Property name="model" type="javax.swing.ComboBoxModel" editor="org.netbeans.modules.form.RADConnectionPropertyEditor">
<Connection code="new DefaultComboBoxModel&lt;&gt;(Arrays.asList(PeripheralInformation.State.values()).stream().filter(state -&gt; state != PeripheralInformation.State.NO_PERIPHERAL).toArray(PeripheralInformation.State[]::new))" type="code"/>
</Property>
</Properties>
<Events>
<EventHandler event="itemStateChanged" listener="java.awt.event.ItemListener" parameters="java.awt.event.ItemEvent" handler="stateComboBoxItemStateChanged"/>
</Events>
<AuxValues>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;PeripheralInformation.State&gt;"/>
</AuxValues>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="1" gridY="0" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="jobProcessingPanel">
<Properties>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="Job processing">
<ResourceString PropertyName="titleX" bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.panel_jobProcessing.border.title" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</TitledBorder>
</Border>
</Property>
</Properties>
<Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
<SubComponents>
<Component class="javax.swing.JRadioButton" name="automaticModeRadioButton">
<Properties>
<Property name="selected" type="boolean" value="true"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingAutomatic.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder bottom="0" left="0" right="0" top="0"/>
</Border>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[0, 0, 0, 0]"/>
</Property>
<Property name="name" type="java.lang.String" value="automaticModeRadioButton" noResource="true"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="automaticModeRadioButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JRadioButton" name="manualModeRadioButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingManual.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EmptyBorderInfo">
<EmptyBorder bottom="0" left="0" right="0" top="0"/>
</Border>
</Property>
<Property name="margin" type="java.awt.Insets" editor="org.netbeans.beaninfo.editors.InsetsEditor">
<Insets value="[0, 0, 0, 0]"/>
</Property>
<Property name="name" type="java.lang.String" value="manualModeRadioButton" noResource="true"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="manualModeRadioButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="0" anchor="17" weightX="1.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="finishCurrentJobButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.button_finishCurrentJob.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="name" type="java.lang.String" value="finishCurrentJobButton" noResource="true"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="finishCurrentJobButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
<Component class="javax.swing.JButton" name="failCurrentJobButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="i18n/org/opentcs/commadapter/peripheral/loopback/Bundle.properties" key="loopbackPeripheralCommAdapterPanel.button_failCurrentJob.text" replaceFormat="java.util.ResourceBundle.getBundle(&quot;{bundleNameSlashes}&quot;).getString(&quot;{key}&quot;)"/>
</Property>
<Property name="enabled" type="boolean" value="false"/>
<Property name="name" type="java.lang.String" value="processCurrentJobButton" noResource="true"/>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="failCurrentJobButtonActionPerformed"/>
</Events>
<Constraints>
<Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
<GridBagConstraints gridX="0" gridY="3" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="0" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
</Constraint>
</Constraints>
</Component>
</SubComponents>
</Container>
</SubComponents>
</Form>

View File

@@ -0,0 +1,299 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import static java.util.Objects.requireNonNull;
import com.google.inject.assistedinject.Assisted;
import jakarta.inject.Inject;
import java.awt.event.ItemEvent;
import java.util.Arrays;
import javax.swing.DefaultComboBoxModel;
import javax.swing.SwingUtilities;
import org.opentcs.access.KernelServicePortal;
import org.opentcs.commadapter.peripheral.loopback.commands.EnableManualModeCommand;
import org.opentcs.commadapter.peripheral.loopback.commands.FinishJobProcessingCommand;
import org.opentcs.commadapter.peripheral.loopback.commands.SetStateCommand;
import org.opentcs.customizations.ServiceCallWrapper;
import org.opentcs.data.model.PeripheralInformation;
import org.opentcs.drivers.peripherals.PeripheralAdapterCommand;
import org.opentcs.drivers.peripherals.PeripheralProcessModel;
import org.opentcs.drivers.peripherals.management.PeripheralCommAdapterPanel;
import org.opentcs.util.CallWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The panel for the loopback peripheral communication adapter.
*/
public class LoopbackPeripheralCommAdapterPanel
extends
PeripheralCommAdapterPanel {
/**
* This class's logger.
*/
private static final Logger LOG
= LoggerFactory.getLogger(LoopbackPeripheralCommAdapterPanel.class);
/**
* The service portal to use.
*/
private final KernelServicePortal servicePortal;
/**
* The call wrapper to use for service calls.
*/
private final CallWrapper callWrapper;
/**
* The comm adapter's process model.
*/
private LoopbackPeripheralProcessModel processModel;
@Inject
@SuppressWarnings("this-escape")
public LoopbackPeripheralCommAdapterPanel(
@Assisted
LoopbackPeripheralProcessModel processModel,
KernelServicePortal servicePortal,
@ServiceCallWrapper
CallWrapper callWrapper
) {
this.processModel = requireNonNull(processModel, "processModel");
this.servicePortal = requireNonNull(servicePortal, "servicePortal");
this.callWrapper = requireNonNull(callWrapper, "callWrapper");
initComponents();
updateComponentsEnabled();
updateComponentContents();
}
@Override
public void processModelChanged(PeripheralProcessModel processModel) {
requireNonNull(processModel, "processModel");
if (!(processModel instanceof LoopbackPeripheralProcessModel)) {
return;
}
SwingUtilities.invokeLater(() -> {
this.processModel = (LoopbackPeripheralProcessModel) processModel;
updateComponentsEnabled();
updateComponentContents();
});
}
private void updateComponentsEnabled() {
boolean enabled = processModel.isCommAdapterEnabled();
stateComboBox.setEnabled(enabled);
finishCurrentJobButton.setEnabled(processModel.isManualModeEnabled());
failCurrentJobButton.setEnabled(processModel.isManualModeEnabled());
}
private void updateComponentContents() {
stateComboBox.setSelectedItem(processModel.getState());
manualModeRadioButton.setSelected(processModel.isManualModeEnabled());
automaticModeRadioButton.setSelected(!processModel.isManualModeEnabled());
}
private void sendCommAdapterCommand(PeripheralAdapterCommand command) {
try {
callWrapper.call(
() -> servicePortal.getPeripheralService()
.sendCommAdapterCommand(processModel.getLocation(), command)
);
}
catch (Exception ex) {
LOG.warn("Error sending comm adapter command '{}'", command, ex);
}
}
// FORMATTER:OFF
// CHECKSTYLE:OFF
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always regenerated
* by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
java.awt.GridBagConstraints gridBagConstraints;
statePanel = new javax.swing.JPanel();
stateLabel = new javax.swing.JLabel();
stateComboBox = new javax.swing.JComboBox<>();
jobProcessingPanel = new javax.swing.JPanel();
automaticModeRadioButton = new javax.swing.JRadioButton();
manualModeRadioButton = new javax.swing.JRadioButton();
finishCurrentJobButton = new javax.swing.JButton();
failCurrentJobButton = new javax.swing.JButton();
java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("i18n/org/opentcs/commadapter/peripheral/loopback/Bundle"); // NOI18N
statePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("loopbackPeripheralCommAdapterPanel.panel_state.border.title"))); // NOI18N
statePanel.setName("statePanel"); // NOI18N
statePanel.setLayout(new java.awt.GridBagLayout());
stateLabel.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
stateLabel.setText(bundle.getString("loopbackPeripheralCommAdapterPanel.label_state.text")); // NOI18N
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 0);
statePanel.add(stateLabel, gridBagConstraints);
stateComboBox.setModel(new DefaultComboBoxModel<>(Arrays.asList(PeripheralInformation.State.values()).stream().filter(state -> state != PeripheralInformation.State.NO_PERIPHERAL).toArray(PeripheralInformation.State[]::new)));
stateComboBox.addItemListener(new java.awt.event.ItemListener() {
public void itemStateChanged(java.awt.event.ItemEvent evt) {
stateComboBoxItemStateChanged(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 1;
gridBagConstraints.gridy = 0;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
statePanel.add(stateComboBox, gridBagConstraints);
jobProcessingPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("loopbackPeripheralCommAdapterPanel.panel_jobProcessing.border.title"))); // NOI18N
jobProcessingPanel.setLayout(new java.awt.GridBagLayout());
automaticModeRadioButton.setSelected(true);
automaticModeRadioButton.setText(bundle.getString("loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingAutomatic.text")); // NOI18N
automaticModeRadioButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
automaticModeRadioButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
automaticModeRadioButton.setName("automaticModeRadioButton"); // NOI18N
automaticModeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
automaticModeRadioButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 0;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0);
jobProcessingPanel.add(automaticModeRadioButton, gridBagConstraints);
manualModeRadioButton.setText(bundle.getString("loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingManual.text")); // NOI18N
manualModeRadioButton.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
manualModeRadioButton.setMargin(new java.awt.Insets(0, 0, 0, 0));
manualModeRadioButton.setName("manualModeRadioButton"); // NOI18N
manualModeRadioButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
manualModeRadioButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 1;
gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
gridBagConstraints.weightx = 1.0;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 0);
jobProcessingPanel.add(manualModeRadioButton, gridBagConstraints);
finishCurrentJobButton.setText(bundle.getString("loopbackPeripheralCommAdapterPanel.button_finishCurrentJob.text")); // NOI18N
finishCurrentJobButton.setEnabled(false);
finishCurrentJobButton.setName("finishCurrentJobButton"); // NOI18N
finishCurrentJobButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
finishCurrentJobButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 2;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 3);
jobProcessingPanel.add(finishCurrentJobButton, gridBagConstraints);
failCurrentJobButton.setText(bundle.getString("loopbackPeripheralCommAdapterPanel.button_failCurrentJob.text")); // NOI18N
failCurrentJobButton.setEnabled(false);
failCurrentJobButton.setName("processCurrentJobButton"); // NOI18N
failCurrentJobButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
failCurrentJobButtonActionPerformed(evt);
}
});
gridBagConstraints = new java.awt.GridBagConstraints();
gridBagConstraints.gridx = 0;
gridBagConstraints.gridy = 3;
gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
gridBagConstraints.insets = new java.awt.Insets(3, 3, 0, 3);
jobProcessingPanel.add(failCurrentJobButton, gridBagConstraints);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
.addComponent(statePanel, javax.swing.GroupLayout.DEFAULT_SIZE, 194, Short.MAX_VALUE)
.addComponent(jobProcessingPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(170, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addContainerGap()
.addComponent(statePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jobProcessingPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(165, Short.MAX_VALUE))
);
getAccessibleContext().setAccessibleName(bundle.getString("loopbackPeripheralCommAdapterPanel.accessibleName")); // NOI18N
}// </editor-fold>//GEN-END:initComponents
// CHECKSTYLE:ON
// FORMATTER:ON
private void manualModeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_manualModeRadioButtonActionPerformed
sendCommAdapterCommand(new EnableManualModeCommand(manualModeRadioButton.isSelected()));
}//GEN-LAST:event_manualModeRadioButtonActionPerformed
private void automaticModeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_automaticModeRadioButtonActionPerformed
sendCommAdapterCommand(new EnableManualModeCommand(!manualModeRadioButton.isSelected()));
}//GEN-LAST:event_automaticModeRadioButtonActionPerformed
private void finishCurrentJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_finishCurrentJobButtonActionPerformed
sendCommAdapterCommand(new FinishJobProcessingCommand(false));
}//GEN-LAST:event_finishCurrentJobButtonActionPerformed
private void stateComboBoxItemStateChanged(java.awt.event.ItemEvent evt) {//GEN-FIRST:event_stateComboBoxItemStateChanged
if (evt.getStateChange() != ItemEvent.SELECTED) {
return;
}
PeripheralInformation.State selectedState
= (PeripheralInformation.State) stateComboBox.getSelectedItem();
if (selectedState == processModel.getState()) {
// If the selection has changed due to an update in the process model (i.e. the user has not
// selected an item in this panel's combo box), we don't want to send a set state command.
return;
}
sendCommAdapterCommand(
new SetStateCommand((PeripheralInformation.State) stateComboBox.getSelectedItem())
);
}//GEN-LAST:event_stateComboBoxItemStateChanged
private void failCurrentJobButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_failCurrentJobButtonActionPerformed
sendCommAdapterCommand(new FinishJobProcessingCommand(true));
}//GEN-LAST:event_failCurrentJobButtonActionPerformed
// FORMATTER:OFF
// CHECKSTYLE:OFF
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JRadioButton automaticModeRadioButton;
private javax.swing.JButton failCurrentJobButton;
private javax.swing.JButton finishCurrentJobButton;
private javax.swing.JPanel jobProcessingPanel;
private javax.swing.JRadioButton manualModeRadioButton;
private javax.swing.JComboBox<PeripheralInformation.State> stateComboBox;
private javax.swing.JLabel stateLabel;
private javax.swing.JPanel statePanel;
// End of variables declaration//GEN-END:variables
// CHECKSTYLE:ON
// FORMATTER:ON
}

View File

@@ -0,0 +1,95 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import static java.util.Objects.requireNonNull;
import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.opentcs.data.model.Location;
import org.opentcs.data.model.TCSResourceReference;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
import org.opentcs.drivers.peripherals.PeripheralProcessModel;
import org.opentcs.drivers.peripherals.management.PeripheralCommAdapterPanel;
import org.opentcs.drivers.peripherals.management.PeripheralCommAdapterPanelFactory;
/**
* A factory for creating {@link LoopbackPeripheralCommAdapterPanel} instances.
*/
public class LoopbackPeripheralCommAdapterPanelFactory
implements
PeripheralCommAdapterPanelFactory {
/**
* The panel components factory to use.
*/
private final LoopbackPeripheralAdapterPanelComponentsFactory panelComponentsFactory;
/**
* Indicates whether this component is initialized or not.
*/
private boolean initialized;
@Inject
public LoopbackPeripheralCommAdapterPanelFactory(
LoopbackPeripheralAdapterPanelComponentsFactory panelComponentsFactory
) {
this.panelComponentsFactory = requireNonNull(panelComponentsFactory, "panelComponentsFactory");
}
@Override
public void initialize() {
if (isInitialized()) {
return;
}
initialized = true;
}
@Override
public boolean isInitialized() {
return initialized;
}
@Override
public void terminate() {
if (!isInitialized()) {
return;
}
initialized = false;
}
@Override
public List<PeripheralCommAdapterPanel> getPanelsFor(
@Nonnull
PeripheralCommAdapterDescription description,
@Nonnull
TCSResourceReference<Location> location,
@Nonnull
PeripheralProcessModel processModel
) {
requireNonNull(description, "description");
requireNonNull(location, "location");
requireNonNull(processModel, "processModel");
if (!providesPanelsFor(description, processModel)) {
return new ArrayList<>();
}
return Arrays.asList(
panelComponentsFactory
.createPanel((LoopbackPeripheralProcessModel) processModel)
);
}
private boolean providesPanelsFor(
PeripheralCommAdapterDescription description,
PeripheralProcessModel processModel
) {
return (description instanceof LoopbackPeripheralCommAdapterDescription)
&& (processModel instanceof LoopbackPeripheralProcessModel);
}
}

View File

@@ -0,0 +1,119 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import java.io.Serializable;
import org.opentcs.data.model.Location;
import org.opentcs.data.model.PeripheralInformation;
import org.opentcs.data.model.TCSResourceReference;
import org.opentcs.drivers.peripherals.PeripheralProcessModel;
/**
* The process model for the loopback peripheral communication adapter.
*/
public class LoopbackPeripheralProcessModel
extends
PeripheralProcessModel
implements
Serializable {
/**
* Whether the peripheral device is manual mode (i.e. the user triggers the job execution).
*/
private final boolean manualModeEnabled;
public LoopbackPeripheralProcessModel(TCSResourceReference<Location> location) {
this(location, false, false, PeripheralInformation.State.UNKNOWN, false);
}
private LoopbackPeripheralProcessModel(
TCSResourceReference<Location> location,
boolean commAdapterEnabled,
boolean commAdapterConnected,
PeripheralInformation.State state,
boolean manualModeEnabled
) {
super(location, commAdapterEnabled, commAdapterConnected, state);
this.manualModeEnabled = manualModeEnabled;
}
@Override
public LoopbackPeripheralProcessModel withLocation(TCSResourceReference<Location> location) {
return new LoopbackPeripheralProcessModel(
location,
isCommAdapterEnabled(),
isCommAdapterConnected(),
getState(),
manualModeEnabled
);
}
@Override
public LoopbackPeripheralProcessModel withCommAdapterEnabled(boolean commAdapterEnabled) {
return new LoopbackPeripheralProcessModel(
getLocation(),
commAdapterEnabled,
isCommAdapterConnected(),
getState(),
manualModeEnabled
);
}
@Override
public LoopbackPeripheralProcessModel withCommAdapterConnected(boolean commAdapterConnected) {
return new LoopbackPeripheralProcessModel(
getLocation(),
isCommAdapterEnabled(),
commAdapterConnected,
getState(),
manualModeEnabled
);
}
@Override
public LoopbackPeripheralProcessModel withState(PeripheralInformation.State state) {
return new LoopbackPeripheralProcessModel(
getLocation(),
isCommAdapterEnabled(),
isCommAdapterConnected(),
state,
manualModeEnabled
);
}
/**
* Returns whether the peripheral device is manual mode (i.e. the user triggers the job
* execution).
*
* @return Whether the peripheral device is manual mode.
*/
public boolean isManualModeEnabled() {
return manualModeEnabled;
}
/**
* Creates a copy of the object, with the given value.
*
* @param manualModeEnabled The value to be set in the copy.
* @return A copy of this object, differing in the given value.
*/
public LoopbackPeripheralProcessModel withManualModeEnabled(boolean manualModeEnabled) {
return new LoopbackPeripheralProcessModel(
getLocation(),
isCommAdapterEnabled(),
isCommAdapterConnected(),
getState(),
manualModeEnabled
);
}
/**
* Used to describe what has changed in a process model.
*/
public enum Attribute {
/**
* Indicates a change of the manual mode enabled property.
*/
MANUAL_MODE_ENABLED,
}
}

View File

@@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback;
import org.opentcs.configuration.ConfigurationEntry;
import org.opentcs.configuration.ConfigurationPrefix;
/**
* Provides methods to configure to {@link LoopbackPeripheralCommAdapter}.
*/
@ConfigurationPrefix(VirtualPeripheralConfiguration.PREFIX)
public interface VirtualPeripheralConfiguration {
/**
* This configuration's prefix.
*/
String PREFIX = "virtualperipheral";
@ConfigurationEntry(
type = "Boolean",
description = "Whether to enable to register/enable the peripheral loopback driver.",
changesApplied = ConfigurationEntry.ChangesApplied.ON_APPLICATION_START,
orderKey = "0_enable"
)
boolean enable();
}

View File

@@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback.commands;
import org.opentcs.commadapter.peripheral.loopback.LoopbackPeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralAdapterCommand;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
/**
* A command to enable/disable the comm adapter's manual mode.
*/
public class EnableManualModeCommand
implements
PeripheralAdapterCommand {
/**
* Whether to enable/disable manual mode.
*/
private final boolean enabled;
/**
* Creates a new instance.
*
* @param enabled Whether to enable/disable manual mode.
*/
public EnableManualModeCommand(boolean enabled) {
this.enabled = enabled;
}
@Override
public void execute(PeripheralCommAdapter adapter) {
if (!(adapter instanceof LoopbackPeripheralCommAdapter)) {
return;
}
LoopbackPeripheralCommAdapter loopbackAdapter = (LoopbackPeripheralCommAdapter) adapter;
loopbackAdapter.enableManualMode(enabled);
}
}

View File

@@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback.commands;
import org.opentcs.commadapter.peripheral.loopback.LoopbackPeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralAdapterCommand;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
/**
* A command to trigger the comm adapter in manual mode and finish the job the simulated peripheral
* device is currently processing.
*/
public class FinishJobProcessingCommand
implements
PeripheralAdapterCommand {
/**
* Whether to fail the execution of the job the (simulated) peripheral device is currently
* processing.
*/
private final boolean failJob;
/**
* Creates a new instance.
*
* @param failJob Whether to fail the execution of the job the (simulated) peripheral device is
* currently processing.
*/
public FinishJobProcessingCommand(boolean failJob) {
this.failJob = failJob;
}
@Override
public void execute(PeripheralCommAdapter adapter) {
if (!(adapter instanceof LoopbackPeripheralCommAdapter)) {
return;
}
LoopbackPeripheralCommAdapter loopbackAdapter = (LoopbackPeripheralCommAdapter) adapter;
loopbackAdapter.triggerJobProcessing(failJob);
}
}

View File

@@ -0,0 +1,46 @@
// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.commadapter.peripheral.loopback.commands;
import static java.util.Objects.requireNonNull;
import jakarta.annotation.Nonnull;
import org.opentcs.commadapter.peripheral.loopback.LoopbackPeripheralCommAdapter;
import org.opentcs.data.model.PeripheralInformation;
import org.opentcs.drivers.peripherals.PeripheralAdapterCommand;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
/**
* A command to set the peripheral device's state.
*/
public class SetStateCommand
implements
PeripheralAdapterCommand {
/**
* The peripheral device state to set.
*/
private final PeripheralInformation.State state;
/**
* Creates a new instance.
*
* @param state The peripheral device state to set.
*/
public SetStateCommand(
@Nonnull
PeripheralInformation.State state
) {
this.state = requireNonNull(state, "state");
}
@Override
public void execute(PeripheralCommAdapter adapter) {
if (!(adapter instanceof LoopbackPeripheralCommAdapter)) {
return;
}
LoopbackPeripheralCommAdapter loopbackAdapter = (LoopbackPeripheralCommAdapter) adapter;
loopbackAdapter.updateState(state);
}
}

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: CC-BY-4.0
loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingManual.text=Manual mode
loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingAutomatic.text=Automatic mode
loopbackPeripheralCommAdapterPanel.panel_state.border.title=Current state
loopbackPeripheralCommAdapterPanel.panel_jobProcessing.border.title=Job processing
loopbackPeripheralCommAdapterPanel.label_state.text=State:
loopbackPeripheralCommAdapterPanel.label_pausePeripheral.text=Pause peripheral:
loopbackPeripheralCommAdapterPanel.button_failCurrentJob.text=Fail current job
loopbackPeripheralCommAdapterPanel.button_finishCurrentJob.text=Finish current job
loopbackPeripheralCommAdapterPanel.accessibleName=Loopback options
loopbackPeripheralCommAdapterDescription.description=Loopback adapter (virtual peripheral)

View File

@@ -0,0 +1,13 @@
# SPDX-FileCopyrightText: The openTCS Authors
# SPDX-License-Identifier: CC-BY-4.0
loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingManual.text=Manuell
loopbackPeripheralCommAdapterPanel.radioButton_jobProcessingAutomatic.text=Automatik
loopbackPeripheralCommAdapterPanel.panel_state.border.title=Aktueller Zustand
loopbackPeripheralCommAdapterPanel.panel_jobProcessing.border.title=Auftragsbearbeitung
loopbackPeripheralCommAdapterPanel.label_state.text=Zustand:
loopbackPeripheralCommAdapterPanel.label_pausePeripheral.text=Peripherie anhalten:
loopbackPeripheralCommAdapterPanel.button_failCurrentJob.text=Aktuellen Auftrag fehlschlagen lassen
loopbackPeripheralCommAdapterPanel.button_finishCurrentJob.text=Aktuellen Auftrag abschlie\u00dfen
loopbackPeripheralCommAdapterPanel.accessibleName=Loopback-Optionen
loopbackPeripheralCommAdapterDescription.description=Loopback-Treiber (virtuelle Peripherie)