001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.hal;
006
007/**
008 * A wrapper around a simulator device handle.
009 *
010 * <p>Teams: if you are using this class, you are likely confusing it for {@link
011 * edu.wpi.first.wpilibj.simulation.SimDeviceSim}.
012 *
013 * <p>Vendors: This class should be used from inside the device class to define the
014 * properties/fields of the device. Use {@link #create} to get a SimDevice object, then use {@link
015 * #createDouble(String, Direction, double)} or similar to define the device's fields. See {@link
016 * edu.wpi.first.wpilibj.ADXRS450_Gyro} for an example implementation.
017 */
018public class SimDevice implements AutoCloseable {
019  /** Sim device direction. */
020  public enum Direction {
021    /** Input direction for simulation devices. */
022    kInput(SimDeviceJNI.kInput),
023    /** Output direction for simulation devices. */
024    kOutput(SimDeviceJNI.kOutput),
025    /** Bidirectional direction for simulation devices. */
026    kBidir(SimDeviceJNI.kBidir);
027
028    public final int m_value;
029
030    Direction(int value) {
031      m_value = value;
032    }
033  }
034
035  /**
036   * Creates a simulated device.
037   *
038   * <p>The device name must be unique. Returns null if the device name already exists. If multiple
039   * instances of the same device are desired, recommend appending the instance/unique identifier in
040   * brackets to the base name, e.g. "device[1]".
041   *
042   * <p>null is returned if not in simulation.
043   *
044   * @param name device name
045   * @return simulated device object
046   */
047  public static SimDevice create(String name) {
048    int handle = SimDeviceJNI.createSimDevice(name);
049    if (handle <= 0) {
050      return null;
051    }
052    return new SimDevice(handle);
053  }
054
055  /**
056   * Creates a simulated device.
057   *
058   * <p>The device name must be unique. Returns null if the device name already exists. This is a
059   * convenience method that appends index in brackets to the device name, e.g. passing index=1
060   * results in "device[1]" for the device name.
061   *
062   * <p>null is returned if not in simulation.
063   *
064   * @param name device name
065   * @param index device index number to append to name
066   * @return simulated device object
067   */
068  public static SimDevice create(String name, int index) {
069    return create(name + "[" + index + "]");
070  }
071
072  /**
073   * Creates a simulated device.
074   *
075   * <p>The device name must be unique. Returns null if the device name already exists. This is a
076   * convenience method that appends index and channel in brackets to the device name, e.g. passing
077   * index=1 and channel=2 results in "device[1,2]" for the device name.
078   *
079   * <p>null is returned if not in simulation.
080   *
081   * @param name device name
082   * @param index device index number to append to name
083   * @param channel device channel number to append to name
084   * @return simulated device object
085   */
086  public static SimDevice create(String name, int index, int channel) {
087    return create(name + "[" + index + "," + channel + "]");
088  }
089
090  /**
091   * Wraps a simulated device handle as returned by SimDeviceJNI.createSimDevice().
092   *
093   * @param handle simulated device handle
094   */
095  public SimDevice(int handle) {
096    m_handle = handle;
097  }
098
099  @Override
100  public void close() {
101    SimDeviceJNI.freeSimDevice(m_handle);
102  }
103
104  /**
105   * Get the internal device handle.
106   *
107   * @return internal handle
108   */
109  public int getNativeHandle() {
110    return m_handle;
111  }
112
113  /**
114   * Get the name of the simulated device.
115   *
116   * @return the name
117   */
118  public String getName() {
119    return SimDeviceJNI.getSimDeviceName(m_handle);
120  }
121
122  /**
123   * Creates a value on the simulated device.
124   *
125   * <p>Returns null if not in simulation.
126   *
127   * @param name value name
128   * @param direction input/output/bidir (from perspective of user code)
129   * @param initialValue initial value
130   * @return simulated value object
131   */
132  public SimValue createValue(String name, Direction direction, HALValue initialValue) {
133    int handle = SimDeviceJNI.createSimValue(m_handle, name, direction.m_value, initialValue);
134    if (handle <= 0) {
135      return null;
136    }
137    return new SimValue(handle);
138  }
139
140  /**
141   * Creates an int value on the simulated device.
142   *
143   * <p>Returns null if not in simulation.
144   *
145   * @param name value name
146   * @param direction input/output/bidir (from perspective of user code)
147   * @param initialValue initial value
148   * @return simulated double value object
149   */
150  public SimInt createInt(String name, Direction direction, int initialValue) {
151    int handle = SimDeviceJNI.createSimValueInt(m_handle, name, direction.m_value, initialValue);
152    if (handle <= 0) {
153      return null;
154    }
155    return new SimInt(handle);
156  }
157
158  /**
159   * Creates a long value on the simulated device.
160   *
161   * <p>Returns null if not in simulation.
162   *
163   * @param name value name
164   * @param direction input/output/bidir (from perspective of user code)
165   * @param initialValue initial value
166   * @return simulated double value object
167   */
168  public SimLong createLong(String name, Direction direction, long initialValue) {
169    int handle = SimDeviceJNI.createSimValueLong(m_handle, name, direction.m_value, initialValue);
170    if (handle <= 0) {
171      return null;
172    }
173    return new SimLong(handle);
174  }
175
176  /**
177   * Creates a double value on the simulated device.
178   *
179   * <p>Returns null if not in simulation.
180   *
181   * @param name value name
182   * @param direction input/output/bidir (from perspective of user code)
183   * @param initialValue initial value
184   * @return simulated double value object
185   */
186  public SimDouble createDouble(String name, Direction direction, double initialValue) {
187    int handle = SimDeviceJNI.createSimValueDouble(m_handle, name, direction.m_value, initialValue);
188    if (handle <= 0) {
189      return null;
190    }
191    return new SimDouble(handle);
192  }
193
194  /**
195   * Creates an enumerated value on the simulated device.
196   *
197   * <p>Enumerated values are always in the range 0 to numOptions-1.
198   *
199   * <p>Returns null if not in simulation.
200   *
201   * @param name value name
202   * @param direction input/output/bidir (from perspective of user code)
203   * @param options array of option descriptions
204   * @param initialValue initial value (selection)
205   * @return simulated enum value object
206   */
207  public SimEnum createEnum(String name, Direction direction, String[] options, int initialValue) {
208    int handle =
209        SimDeviceJNI.createSimValueEnum(m_handle, name, direction.m_value, options, initialValue);
210    if (handle <= 0) {
211      return null;
212    }
213    return new SimEnum(handle);
214  }
215
216  /**
217   * Creates an enumerated value on the simulated device with double values.
218   *
219   * <p>Enumerated values are always in the range 0 to numOptions-1.
220   *
221   * <p>Returns null if not in simulation.
222   *
223   * @param name value name
224   * @param direction input/output/bidir (from perspective of user code)
225   * @param options array of option descriptions
226   * @param optionValues array of option values (must be the same size as options)
227   * @param initialValue initial value (selection)
228   * @return simulated enum value object
229   */
230  public SimEnum createEnumDouble(
231      String name, Direction direction, String[] options, double[] optionValues, int initialValue) {
232    int handle =
233        SimDeviceJNI.createSimValueEnumDouble(
234            m_handle, name, direction.m_value, options, optionValues, initialValue);
235    if (handle <= 0) {
236      return null;
237    }
238    return new SimEnum(handle);
239  }
240
241  /**
242   * Creates a boolean value on the simulated device.
243   *
244   * <p>Returns null if not in simulation.
245   *
246   * @param name value name
247   * @param direction input/output/bidir (from perspective of user code)
248   * @param initialValue initial value
249   * @return simulated boolean value object
250   */
251  public SimBoolean createBoolean(String name, Direction direction, boolean initialValue) {
252    int handle =
253        SimDeviceJNI.createSimValueBoolean(m_handle, name, direction.m_value, initialValue);
254    if (handle <= 0) {
255      return null;
256    }
257    return new SimBoolean(handle);
258  }
259
260  private final int m_handle;
261}