All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentcs.kernel.peripherals.PeripheralAttachmentManager Maven / Gradle / Ivy

// SPDX-FileCopyrightText: The openTCS Authors
// SPDX-License-Identifier: MIT
package org.opentcs.kernel.peripherals;

import static java.util.Objects.requireNonNull;

import jakarta.annotation.Nonnull;
import jakarta.inject.Inject;
import java.util.List;
import org.opentcs.components.Lifecycle;
import org.opentcs.components.kernel.services.InternalPeripheralService;
import org.opentcs.customizations.ApplicationEventBus;
import org.opentcs.data.model.Location;
import org.opentcs.data.model.TCSResourceReference;
import org.opentcs.drivers.peripherals.PeripheralCommAdapter;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterDescription;
import org.opentcs.drivers.peripherals.PeripheralCommAdapterFactory;
import org.opentcs.drivers.peripherals.PeripheralProcessModel;
import org.opentcs.drivers.peripherals.management.PeripheralAttachmentEvent;
import org.opentcs.drivers.peripherals.management.PeripheralAttachmentInformation;
import org.opentcs.drivers.peripherals.management.PeripheralProcessModelEvent;
import org.opentcs.kernel.KernelApplicationConfiguration;
import org.opentcs.util.event.EventHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Manages attachment and detachment of peripheral communication adapters to location.
 */
public class PeripheralAttachmentManager
    implements
      Lifecycle {

  /**
   * This class's logger.
   */
  private static final Logger LOG = LoggerFactory.getLogger(PeripheralAttachmentManager.class);
  /**
   * This class's configuration.
   */
  private final KernelApplicationConfiguration configuration;
  /**
   * The peripheral service.
   */
  private final InternalPeripheralService peripheralService;
  /**
   * The peripheral controller pool.
   */
  private final LocalPeripheralControllerPool controllerPool;
  /**
   * The peripheral comm adapter registry.
   */
  private final PeripheralCommAdapterRegistry commAdapterRegistry;
  /**
   * The pool of peripheral entries.
   */
  private final PeripheralEntryPool peripheralEntryPool;
  /**
   * The handler to send events to.
   */
  private final EventHandler eventHandler;
  /**
   * Whether the attachment manager is initialized or not.
   */
  private boolean initialized;

  /**
   * Creates a new instance.
   *
   * @param peripheralService The peripheral service.
   * @param controllerPool The peripheral controller pool.
   * @param commAdapterRegistry The peripheral comm adapter registry.
   * @param peripheralEntryPool The pool of peripheral entries.
   * @param eventHandler The handler to send events to.
   * @param configuration This class's configuration.
   */
  @Inject
  public PeripheralAttachmentManager(
      @Nonnull
      InternalPeripheralService peripheralService,
      @Nonnull
      LocalPeripheralControllerPool controllerPool,
      @Nonnull
      PeripheralCommAdapterRegistry commAdapterRegistry,
      @Nonnull
      PeripheralEntryPool peripheralEntryPool,
      @Nonnull
      @ApplicationEventBus
      EventHandler eventHandler,
      @Nonnull
      KernelApplicationConfiguration configuration
  ) {
    this.peripheralService = requireNonNull(peripheralService, "peripheralService");
    this.controllerPool = requireNonNull(controllerPool, "controllerPool");
    this.commAdapterRegistry = requireNonNull(commAdapterRegistry, "commAdapterRegistry");
    this.peripheralEntryPool = requireNonNull(peripheralEntryPool, "peripheralEntryPool");
    this.eventHandler = requireNonNull(eventHandler, "eventHandler");
    this.configuration = requireNonNull(configuration, "configuration");
  }

  @Override
  public void initialize() {
    if (isInitialized()) {
      return;
    }

    commAdapterRegistry.initialize();
    peripheralEntryPool.initialize();

    autoAttachAllAdapters();
    LOG.debug("Locations attached: {}", peripheralEntryPool.getEntries());

    if (configuration.autoEnablePeripheralDriversOnStartup()) {
      autoEnableAllAdapters();
    }

    initialized = true;
  }

  @Override
  public boolean isInitialized() {
    return initialized;
  }

  @Override
  public void terminate() {
    if (!isInitialized()) {
      LOG.debug("Not initialized.");
      return;
    }

    // Disable and terminate all attached drivers to clean up.
    disableAndTerminateAllAdapters();
    peripheralEntryPool.terminate();
    commAdapterRegistry.terminate();

    initialized = false;
  }

  /**
   * Attaches a peripheral comm adapter to a location.
   *
   * @param location The location to attach to.
   * @param description The description of the comm adapter to attach.
   */
  public void attachAdapterToLocation(
      @Nonnull
      TCSResourceReference location,
      @Nonnull
      PeripheralCommAdapterDescription description
  ) {
    requireNonNull(location, "location");
    requireNonNull(description, "description");

    attachAdapterToLocation(
        peripheralEntryPool.getEntryFor(location),
        commAdapterRegistry.findFactoryFor(description)
    );
  }

  /**
   * Returns the attachment information for a location.
   *
   * @param location The location to get attachment information about.
   * @return The attachment information for a location.
   */
  @Nonnull
  public PeripheralAttachmentInformation getAttachmentInformation(
      @Nonnull
      TCSResourceReference location
  ) {
    requireNonNull(location, "location");

    PeripheralEntry entry = peripheralEntryPool.getEntryFor(location);
    return new PeripheralAttachmentInformation(
        entry.getLocation(),
        entry.getAvailableCommAdapters(),
        entry.getCommAdapterFactory().getDescription()
    );
  }

  private void attachAdapterToLocation(
      PeripheralEntry entry,
      PeripheralCommAdapterFactory factory
  ) {
    requireNonNull(entry, "entry");
    requireNonNull(factory, "factory");

    LOG.info(
        "Attaching peripheral comm adapter: '{}' -- '{}'...",
        entry.getLocation().getName(),
        factory.getClass().getName()
    );

    Location location = peripheralService.fetchObject(Location.class, entry.getLocation());
    PeripheralCommAdapter commAdapter = factory.getAdapterFor(location);
    if (commAdapter == null) {
      LOG.warn(
          "Factory {} did not provide adapter for location {}, ignoring.",
          factory,
          entry.getLocation().getName()
      );
      return;
    }

    // Perform a cleanup for the old adapter.
    disableAndTerminateAdapter(entry);
    controllerPool.detachPeripheralController(entry.getLocation());

    commAdapter.initialize();
    controllerPool.attachPeripheralController(entry.getLocation(), commAdapter);

    entry.setCommAdapterFactory(factory);
    entry.setCommAdapter(commAdapter);

    // Publish events about the new attached adapter.
    eventHandler.onEvent(
        new PeripheralAttachmentEvent(
            entry.getLocation(),
            new PeripheralAttachmentInformation(
                entry.getLocation(),
                entry.getAvailableCommAdapters(),
                entry.getCommAdapterFactory().getDescription()
            )
        )
    );
    eventHandler.onEvent(
        new PeripheralProcessModelEvent(
            entry.getLocation(),
            PeripheralProcessModel.Attribute.LOCATION.name(),
            entry.getProcessModel()
        )
    );
  }

  private void autoAttachAdapterToLocation(PeripheralEntry peripheralEntry) {
    // Do not auto-attach if there is already a (real) comm adapter attached to the location.
    if (!(peripheralEntry.getCommAdapter() instanceof NullPeripheralCommAdapter)) {
      return;
    }

    Location location = peripheralService.fetchObject(
        Location.class,
        peripheralEntry.getLocation()
    );
    List factories = commAdapterRegistry.findFactoriesFor(location);
    if (!factories.isEmpty()) {
      LOG.debug(
          "Attaching {} to first available adapter: {}.",
          peripheralEntry.getLocation().getName(),
          factories.get(0).getDescription().getDescription()
      );
      attachAdapterToLocation(peripheralEntry, factories.get(0));
    }
  }

  private void autoAttachAllAdapters() {
    peripheralEntryPool.getEntries().forEach((location, entry) -> {
      autoAttachAdapterToLocation(entry);
    });
  }

  private void disableAndTerminateAdapter(PeripheralEntry peripheralEntry) {
    peripheralEntry.getCommAdapter().disable();
    peripheralEntry.getCommAdapter().terminate();
  }

  private void autoEnableAllAdapters() {
    peripheralEntryPool.getEntries().values().stream()
        .map(entry -> entry.getCommAdapter())
        .filter(adapter -> !adapter.isEnabled())
        .forEach(adapter -> adapter.enable());
  }

  private void disableAndTerminateAllAdapters() {
    LOG.debug("Detaching peripheral communication adapters...");
    peripheralEntryPool.getEntries().forEach((location, entry) -> {
      disableAndTerminateAdapter(entry);
    });
    LOG.debug("Detached peripheral communication adapters");
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy