001/*----------------------------------------------------------------------------*/
002/* Copyright (c) 2008-2018 FIRST. All Rights Reserved.                        */
003/* Open Source Software - may be modified and shared by FRC teams. The code   */
004/* must be accompanied by the FIRST BSD license file in the root directory of */
005/* the project.                                                               */
006/*----------------------------------------------------------------------------*/
007
008package edu.wpi.first.wpilibj;
009
010import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType;
011import edu.wpi.first.wpilibj.hal.HAL;
012import edu.wpi.first.wpilibj.hal.SolenoidJNI;
013import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder;
014
015/**
016 * Solenoid class for running high voltage Digital Output on the PCM.
017 *
018 * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any
019 * device within the current spec of the PCM.
020 */
021public class Solenoid extends SolenoidBase implements Sendable {
022  private final int m_channel; // The channel to control.
023  private int m_solenoidHandle;
024
025  /**
026   * Constructor using the default PCM ID (defaults to 0).
027   *
028   * @param channel The channel on the PCM to control (0..7).
029   */
030  public Solenoid(final int channel) {
031    this(SensorBase.getDefaultSolenoidModule(), channel);
032  }
033
034  /**
035   * Constructor.
036   *
037   * @param moduleNumber The CAN ID of the PCM the solenoid is attached to.
038   * @param channel      The channel on the PCM to control (0..7).
039   */
040  public Solenoid(final int moduleNumber, final int channel) {
041    super(moduleNumber);
042    m_channel = channel;
043
044    SensorBase.checkSolenoidModule(m_moduleNumber);
045    SensorBase.checkSolenoidChannel(m_channel);
046
047    int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
048    m_solenoidHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
049
050    HAL.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber);
051    setName("Solenoid", m_moduleNumber, m_channel);
052  }
053
054  /**
055   * Destructor.
056   */
057  @Override
058  public synchronized void free() {
059    super.free();
060    SolenoidJNI.freeSolenoidPort(m_solenoidHandle);
061    m_solenoidHandle = 0;
062  }
063
064  /**
065   * Set the value of a solenoid.
066   *
067   * @param on True will turn the solenoid output on. False will turn the solenoid output off.
068   */
069  public void set(boolean on) {
070    SolenoidJNI.setSolenoid(m_solenoidHandle, on);
071  }
072
073  /**
074   * Read the current value of the solenoid.
075   *
076   * @return True if the solenoid output is on or false if the solenoid output is off.
077   */
078  public boolean get() {
079    return SolenoidJNI.getSolenoid(m_solenoidHandle);
080  }
081
082  /**
083   * Check if solenoid is blacklisted. If a solenoid is shorted, it is added to the blacklist and
084   * disabled until power cycle, or until faults are cleared.
085   *
086   * @return If solenoid is disabled due to short.
087   * @see #clearAllPCMStickyFaults()
088   */
089  public boolean isBlackListed() {
090    int value = getPCMSolenoidBlackList() & (1 << m_channel);
091    return value != 0;
092  }
093
094  /**
095   * Set the pulse duration in the PCM. This is used in conjunction with
096   * the startPulse method to allow the PCM to control the timing of a pulse.
097   * The timing can be controlled in 0.01 second increments.
098   *
099   * @param durationSeconds The duration of the pulse, from 0.01 to 2.55 seconds.
100   *
101   * @see #startPulse()
102   */
103  public void setPulseDuration(double durationSeconds) {
104    long durationMS = (long) (durationSeconds * 1000);
105    SolenoidJNI.setOneShotDuration(m_solenoidHandle, durationMS);
106  }
107
108  /**
109   * Trigger the PCM to generate a pulse of the duration set in
110   * setPulseDuration.
111   *
112   * @see #setPulseDuration(double)
113   */
114  public void startPulse() {
115    SolenoidJNI.fireOneShot(m_solenoidHandle);
116  }
117
118  @Override
119  public void initSendable(SendableBuilder builder) {
120    builder.setSmartDashboardType("Solenoid");
121    builder.setSafeState(() -> set(false));
122    builder.addBooleanProperty("Value", this::get, this::set);
123  }
124}