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

org.opentcs.drivers.vehicle.VehicleProcessModel Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/**
 * Copyright (c) The openTCS Authors.
 *
 * This program is free software and subject to the MIT license. (For details,
 * see the licensing information (LICENSE.txt) you should have received with
 * this copy of the software.)
 */
package org.opentcs.drivers.vehicle;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.util.LinkedList;
import java.util.List;
import static java.util.Objects.requireNonNull;
import java.util.Queue;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.opentcs.data.TCSObjectReference;
import org.opentcs.data.model.Triple;
import org.opentcs.data.model.Vehicle;
import org.opentcs.data.notification.UserNotification;

/**
 * An observable model of a vehicle's and its comm adapter's attributes.
 *
 * @author Iryna Felko (Fraunhofer IML)
 * @author Stefan Walter (Fraunhofer IML)
 */
public class VehicleProcessModel {

  /**
   * The maximum number of notifications we want to keep.
   */
  private static final int MAX_NOTIFICATION_COUNT = 100;
  /**
   * A copy of the kernel's Vehicle instance.
   */
  private final Vehicle vehicle;
  /**
   * A reference to the vehicle.
   */
  private final TCSObjectReference vehicleReference;
  /**
   * Used for implementing property change events.
   */
  private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
  /**
   * Whether the comm adapter is currently enabled.
   */
  private boolean commAdapterEnabled;
  /**
   * Whether the comm adapter is currently connected to the vehicle.
   */
  private boolean commAdapterConnected;
  /**
   * The name of the vehicle's current position.
   */
  private String vehiclePosition;
  /**
   * User notifications published by the comm adapter.
   */
  private final Queue notifications = new LinkedList<>();
  /**
   * The vehicle's precise position.
   */
  private Triple precisePosition;
  /**
   * The vehicle's orientation angle.
   */
  private double orientationAngle = Double.NaN;
  /**
   * The vehicle's energy level.
   */
  private int energyLevel = 100;
  /**
   * The vehicle's load handling devices (state).
   */
  private List loadHandlingDevices = new LinkedList<>();
  /**
   * The vehicle's current state.
   */
  private Vehicle.State state = Vehicle.State.UNKNOWN;

  /**
   * Creates a new instance.
   *
   * @param attachedVehicle The vehicle attached to the new instance.
   */
  public VehicleProcessModel(@Nonnull Vehicle attachedVehicle) {
    this.vehicle = requireNonNull(attachedVehicle, "attachedVehicle");
    this.vehicleReference = vehicle.getReference();
  }

  /**
   * Registers a new property change listener with this model.
   *
   * @param listener The listener to be registered.
   */
  public void addPropertyChangeListener(PropertyChangeListener listener) {
    pcs.addPropertyChangeListener(listener);
  }

  /**
   * Unregisters a property change listener from this model.
   *
   * @param listener The listener to be unregistered.
   */
  public void removePropertyChangeListener(PropertyChangeListener listener) {
    pcs.removePropertyChangeListener(listener);
  }

  /**
   * Returns a reference to the vehicle.
   *
   * @return A reference to the vehicle.
   */
  @Nonnull
  public TCSObjectReference getVehicleReference() {
    return vehicleReference;
  }

  /**
   * Returns the vehicle's name.
   *
   * @return The vehicle's name.
   */
  @Nonnull
  public String getName() {
    return vehicleReference.getName();
  }

  /**
   * Returns user notifications published by the comm adapter.
   *
   * @return The notifications.
   */
  @Nonnull
  public Queue getNotifications() {
    return notifications;
  }

  /**
   * Publishes an user notification.
   *
   * @param notification The notification to be published.
   */
  public void publishUserNotification(@Nonnull UserNotification notification) {
    requireNonNull(notification, "notification");

    notifications.add(notification);
    while (notifications.size() > MAX_NOTIFICATION_COUNT) {
      notifications.remove();
    }

    getPropertyChangeSupport().firePropertyChange(Attribute.USER_NOTIFICATION.name(),
                                                  null,
                                                  notification);
  }

  /**
   * Publishes an event via the kernel's event mechanism.
   *
   * @param event The event to be published.
   */
  public void publishEvent(@Nonnull VehicleCommAdapterEvent event) {
    requireNonNull(event, "event");

    getPropertyChangeSupport().firePropertyChange(Attribute.COMM_ADAPTER_EVENT.name(),
                                                  null,
                                                  event);
  }

  /**
   * Indicates whether the comm adapter is currently enabled or not.
   *
   * @return true if, and only if, the comm adapter is currently enabled.
   */
  public boolean isCommAdapterEnabled() {
    return commAdapterEnabled;
  }

  /**
   * Sets the comm adapter's enabled flag.
   *
   * @param commAdapterEnabled The new value.
   */
  public void setCommAdapterEnabled(boolean commAdapterEnabled) {
    boolean oldValue = this.commAdapterEnabled;
    this.commAdapterEnabled = commAdapterEnabled;

    getPropertyChangeSupport().firePropertyChange(Attribute.COMM_ADAPTER_ENABLED.name(),
                                                  oldValue,
                                                  commAdapterEnabled);
  }

  /**
   * Indicates whether the comm adapter is currently connected or not.
   *
   * @return true if, and only if, the comm adapter is currently connected.
   */
  public boolean isCommAdapterConnected() {
    return commAdapterConnected;
  }

  /**
   * Sets the comm adapter's connected flag.
   *
   * @param commAdapterConnected The new value.
   */
  public void setCommAdapterConnected(boolean commAdapterConnected) {
    boolean oldValue = this.commAdapterConnected;
    this.commAdapterConnected = commAdapterConnected;

    getPropertyChangeSupport().firePropertyChange(Attribute.COMM_ADAPTER_CONNECTED.name(),
                                                  oldValue,
                                                  commAdapterConnected);
  }

  /**
   * Returns the vehicle's current position.
   *
   * @return The position.
   */
  @Nullable
  public String getVehiclePosition() {
    return vehiclePosition;
  }

  /**
   * Updates the vehicle's current position.
   *
   * @param position The new position
   */
  public void setVehiclePosition(@Nullable String position) {
    // Otherwise update the position, notify listeners and let the kernel know.
    String oldValue = this.vehiclePosition;
    vehiclePosition = position;

    getPropertyChangeSupport().firePropertyChange(Attribute.POSITION.name(),
                                                  oldValue,
                                                  position);
  }

  /**
   * Returns the vehicle's precise position.
   *
   * @return The vehicle's precise position.
   */
  @Nullable
  public Triple getVehiclePrecisePosition() {
    return precisePosition;
  }

  /**
   * Sets the vehicle's precise position.
   *
   * @param position The new position.
   */
  public void setVehiclePrecisePosition(@Nullable Triple position) {
    // Otherwise update the position, notify listeners and let the kernel know.
    Triple oldValue = this.precisePosition;
    this.precisePosition = position;

    getPropertyChangeSupport().firePropertyChange(Attribute.PRECISE_POSITION.name(),
                                                  oldValue,
                                                  position);
  }

  /**
   * Returns the vehicle's current orientation angle.
   *
   * @return The vehicle's current orientation angle.
   * @see Vehicle#getOrientationAngle()
   */
  public double getVehicleOrientationAngle() {
    return orientationAngle;
  }

  /**
   * Sets the vehicle's current orientation angle.
   *
   * @param angle The new angle
   */
  public void setVehicleOrientationAngle(double angle) {
    double oldValue = this.orientationAngle;
    this.orientationAngle = angle;

    getPropertyChangeSupport().firePropertyChange(Attribute.ORIENTATION_ANGLE.name(),
                                                  oldValue,
                                                  angle);
  }

  /**
   * Returns the vehicle's current energy level.
   *
   * @return The vehicle's current energy level.
   */
  public int getVehicleEnergyLevel() {
    return energyLevel;
  }

  /**
   * Sets the vehicle's current energy level.
   *
   * @param newLevel The new level.
   */
  public void setVehicleEnergyLevel(int newLevel) {
    int oldValue = this.energyLevel;
    this.energyLevel = newLevel;

    getPropertyChangeSupport().firePropertyChange(Attribute.ENERGY_LEVEL.name(),
                                                  oldValue,
                                                  newLevel);
  }

  /**
   * Returns the vehicle's load handling devices.
   *
   * @return The vehicle's load handling devices.
   */
  @Nonnull
  public List getVehicleLoadHandlingDevices() {
    return loadHandlingDevices;
  }

  /**
   * Sets the vehicle's load handling devices.
   *
   * @param devices The new devices
   */
  public void setVehicleLoadHandlingDevices(@Nonnull List devices) {
    List devs = new LinkedList<>();
    for (LoadHandlingDevice lhd : devices) {
      devs.add(new LoadHandlingDevice(lhd));
    }
    List oldValue = this.loadHandlingDevices;
    this.loadHandlingDevices = devs;

    getPropertyChangeSupport().firePropertyChange(Attribute.LOAD_HANDLING_DEVICES.name(),
                                                  oldValue,
                                                  devs);
  }

  /**
   * Sets a property of the vehicle.
   *
   * @param key The property's key.
   * @param value The property's new value.
   */
  public void setVehicleProperty(@Nonnull String key, @Nullable String value) {
    getPropertyChangeSupport().firePropertyChange(Attribute.VEHICLE_PROPERTY.name(),
                                                  null,
                                                  new VehiclePropertyUpdate(key, value));
  }

  /**
   * Returns the vehicle's current state.
   *
   * @return The state
   */
  @Nonnull
  public Vehicle.State getVehicleState() {
    return state;
  }

  /**
   * Sets the vehicle's current state.
   *
   * @param newState The new state
   */
  public void setVehicleState(@Nonnull Vehicle.State newState) {
    Vehicle.State oldState = this.state;
    this.state = newState;

    getPropertyChangeSupport().firePropertyChange(Attribute.STATE.name(), oldState, newState);

    if (oldState != Vehicle.State.ERROR && newState == Vehicle.State.ERROR) {
      publishUserNotification(new UserNotification(getName(),
                                                   "Vehicle state changed to ERROR",
                                                   UserNotification.Level.NOTEWORTHY));
    }
    else if (oldState == Vehicle.State.ERROR && newState != Vehicle.State.ERROR) {
      publishUserNotification(new UserNotification(getName(),
                                                   "Vehicle state is no longer ERROR",
                                                   UserNotification.Level.NOTEWORTHY));
    }
  }

  /**
   * Sets a property of the transport order the vehicle is currently processing.
   *
   * @param key The property's key.
   * @param value The property's new value.
   */
  public void setTransportOrderProperty(@Nonnull String key, @Nullable String value) {
    // XXX Should check if property already has the new value.
    getPropertyChangeSupport().firePropertyChange(Attribute.TRANSPORT_ORDER_PROPERTY.name(),
                                                  null,
                                                  new TransportOrderPropertyUpdate(key, value));
  }

  /**
   * Notifies observers that the given command has been added to the comm adapter's command queue.
   *
   * @param enqueuedCommand The command that has been added to the queue.
   */
  public void commandEnqueued(@Nonnull MovementCommand enqueuedCommand) {
    getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_ENQUEUED.name(),
                                                  null,
                                                  enqueuedCommand);
  }

  /**
   * Notifies observers that the given command has been sent to the associated vehicle.
   *
   * @param sentCommand The command that has been sent to the vehicle.
   */
  public void commandSent(@Nonnull MovementCommand sentCommand) {
    getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_SENT.name(),
                                                  null,
                                                  sentCommand);
  }

  /**
   * Notifies observers that the given command has been executed by the comm adapter/vehicle.
   *
   * @param executedCommand The command that has been executed.
   */
  public void commandExecuted(@Nonnull MovementCommand executedCommand) {
    getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_EXECUTED.name(),
                                                  null,
                                                  executedCommand);
  }

  /**
   * Notifies observers that the given command could not be executed by the comm adapter/vehicle.
   *
   * @param failedCommand The command that could not be executed.
   */
  public void commandFailed(@Nonnull MovementCommand failedCommand) {
    getPropertyChangeSupport().firePropertyChange(Attribute.COMMAND_FAILED.name(),
                                                  null,
                                                  failedCommand);
  }

  protected PropertyChangeSupport getPropertyChangeSupport() {
    return pcs;
  }

  /**
   * A notification object sent to observers to indicate a change of a property.
   */
  public static class PropertyUpdate {

    /**
     * The property's key.
     */
    private final String key;
    /**
     * The property's new value.
     */
    private final String value;

    /**
     * Creates a new instance.
     *
     * @param key The key.
     * @param value The new value.
     */
    public PropertyUpdate(String key, String value) {
      this.key = requireNonNull(key, "key");
      this.value = value;
    }

    /**
     * Returns the property's key.
     *
     * @return The property's key.
     */
    public String getKey() {
      return key;
    }

    /**
     * Returns the property's new value.
     *
     * @return The property's new value.
     */
    public String getValue() {
      return value;
    }
  }

  /**
   * A notification object sent to observers to indicate a change of a vehicle's property.
   */
  public static class VehiclePropertyUpdate
      extends PropertyUpdate {

    /**
     * Creates a new instance.
     *
     * @param key The property's key.
     * @param value The new value.
     */
    public VehiclePropertyUpdate(String key, String value) {
      super(key, value);
    }
  }

  /**
   * A notification object sent to observers to indicate a change of a transport order's property.
   */
  public static class TransportOrderPropertyUpdate
      extends PropertyUpdate {

    /**
     * Creates a new instance.
     *
     * @param key The property's key.
     * @param value The new value.
     */
    public TransportOrderPropertyUpdate(String key, String value) {
      super(key, value);
    }
  }

  /**
   * Notification arguments to indicate some change.
   */
  public enum Attribute {
    /**
     * Indicates a change of the comm adapter's enabled setting.
     */
    COMM_ADAPTER_ENABLED,
    /**
     * Indicates a change of the comm adapter's connected setting.
     */
    COMM_ADAPTER_CONNECTED,
    /**
     * Indicates a change of the vehicle's position.
     */
    POSITION,
    /**
     * Indicates a change of the vehicle's precise position.
     */
    PRECISE_POSITION,
    /**
     * Indicates a change of the vehicle's orientation angle.
     */
    ORIENTATION_ANGLE,
    /**
     * Indicates a change of the vehicle's energy level.
     */
    ENERGY_LEVEL,
    /**
     * Indicates a change of the vehicle's load handling devices.
     */
    LOAD_HANDLING_DEVICES,
    /**
     * Indicates a change of the vehicle's state.
     */
    STATE,
    /**
     * Indicates a new user notification was published.
     */
    USER_NOTIFICATION,
    /**
     * Indicates a new comm adapter event was published.
     */
    COMM_ADAPTER_EVENT,
    /**
     * Indicates a command was enqueued.
     */
    COMMAND_ENQUEUED,
    /**
     * Indicates a command was sent.
     */
    COMMAND_SENT,
    /**
     * Indicates a command was executed successfully.
     */
    COMMAND_EXECUTED,
    /**
     * Indicates a command failed.
     */
    COMMAND_FAILED,
    /**
     * Indicates a change of a vehicle property.
     */
    VEHICLE_PROPERTY,
    /**
     * Indicates a change of a transport order property.
     */
    TRANSPORT_ORDER_PROPERTY;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy