001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2017. 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.livewindow.LiveWindow;
014import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
015import edu.wpi.first.wpilibj.tables.ITable;
016import edu.wpi.first.wpilibj.tables.ITableListener;
017
018/**
019 * Solenoid class for running high voltage Digital Output on the PCM.
020 *
021 * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any
022 * device within the current spec of the PCM.
023 */
024public class Solenoid extends SolenoidBase implements LiveWindowSendable {
025
026  private final int m_channel; // The channel to control.
027  private int m_solenoidHandle;
028
029  /**
030   * Constructor using the default PCM ID (defaults to 0).
031   *
032   * @param channel The channel on the PCM to control (0..7).
033   */
034  public Solenoid(final int channel) {
035    this(getDefaultSolenoidModule(), channel);
036  }
037
038  /**
039   * Constructor.
040   *
041   * @param moduleNumber The CAN ID of the PCM the solenoid is attached to.
042   * @param channel      The channel on the PCM to control (0..7).
043   */
044  public Solenoid(final int moduleNumber, final int channel) {
045    super(moduleNumber);
046    m_channel = channel;
047
048    checkSolenoidModule(m_moduleNumber);
049    checkSolenoidChannel(m_channel);
050
051    int portHandle = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
052    m_solenoidHandle = SolenoidJNI.initializeSolenoidPort(portHandle);
053
054    LiveWindow.addActuator("Solenoid", m_moduleNumber, m_channel, this);
055    HAL.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber);
056  }
057
058  /**
059   * Destructor.
060   */
061  public synchronized void free() {
062    SolenoidJNI.freeSolenoidPort(m_solenoidHandle);
063    m_solenoidHandle = 0;
064    if (m_table != null) {
065      m_table.removeTableListener(m_tableListener);
066    }
067    super.free();
068  }
069
070  /**
071   * Set the value of a solenoid.
072   *
073   * @param on True will turn the solenoid output on. False will turn the solenoid output off.
074   */
075  public void set(boolean on) {
076    SolenoidJNI.setSolenoid(m_solenoidHandle, on);
077  }
078
079  /**
080   * Read the current value of the solenoid.
081   *
082   * @return True if the solenoid output is on or false if the solenoid output is off.
083   */
084  public boolean get() {
085    return SolenoidJNI.getSolenoid(m_solenoidHandle);
086  }
087
088  /**
089   * Check if solenoid is blacklisted. If a solenoid is shorted, it is added to the blacklist and
090   * disabled until power cycle, or until faults are cleared.
091   *
092   * @return If solenoid is disabled due to short.
093   * @see #clearAllPCMStickyFaults()
094   */
095  public boolean isBlackListed() {
096    int value = getPCMSolenoidBlackList() & (1 << m_channel);
097    return value != 0;
098  }
099
100  /*
101   * Live Window code, only does anything if live window is activated.
102   */
103  public String getSmartDashboardType() {
104    return "Solenoid";
105  }
106
107  private ITable m_table;
108  private ITableListener m_tableListener;
109
110  @Override
111  public void initTable(ITable subtable) {
112    m_table = subtable;
113    updateTable();
114  }
115
116  @Override
117  public ITable getTable() {
118    return m_table;
119  }
120
121  @Override
122  public void updateTable() {
123    if (m_table != null) {
124      m_table.putBoolean("Value", get());
125    }
126  }
127
128  @Override
129  public void startLiveWindowMode() {
130    set(false); // Stop for safety
131    m_tableListener = (source, key, value, isNew) -> set((Boolean) value);
132    m_table.addTableListener("Value", m_tableListener, true);
133  }
134
135  @Override
136  public void stopLiveWindowMode() {
137    set(false); // Stop for safety
138    // TODO: Broken, should only remove the listener from "Value" only.
139    m_table.removeTableListener(m_tableListener);
140  }
141}