001/*----------------------------------------------------------------------------*/
002/* Copyright (c) FIRST 2008-2012. 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 java.nio.ByteBuffer;
011import java.nio.ByteOrder;
012
013import edu.wpi.first.wpilibj.communication.FRCNetworkCommunicationsLibrary.tResourceType;
014import edu.wpi.first.wpilibj.communication.UsageReporting;
015import edu.wpi.first.wpilibj.hal.HALUtil;
016import edu.wpi.first.wpilibj.hal.SolenoidJNI;
017import edu.wpi.first.wpilibj.livewindow.LiveWindow;
018import edu.wpi.first.wpilibj.livewindow.LiveWindowSendable;
019import edu.wpi.first.wpilibj.tables.ITable;
020import edu.wpi.first.wpilibj.tables.ITableListener;
021import edu.wpi.first.wpilibj.util.AllocationException;
022import edu.wpi.first.wpilibj.util.CheckedAllocationException;
023
024/**
025 * Solenoid class for running high voltage Digital Output.
026 *
027 * The Solenoid class is typically used for pneumatics solenoids, but could be used
028 * for any device within the current spec of the PCM.
029 */
030public class Solenoid extends SolenoidBase implements LiveWindowSendable {
031
032    private int m_channel; ///< The channel to control.
033    private ByteBuffer m_solenoid_port;
034
035    /**
036     * Common function to implement constructor behavior.
037     */
038    private synchronized void initSolenoid() {
039        checkSolenoidModule(m_moduleNumber);
040        checkSolenoidChannel(m_channel);
041
042                ByteBuffer status = ByteBuffer.allocateDirect(4);
043                status.order(ByteOrder.LITTLE_ENDIAN);
044
045        ByteBuffer port = SolenoidJNI.getPortWithModule((byte) m_moduleNumber, (byte) m_channel);
046        m_solenoid_port = SolenoidJNI.initializeSolenoidPort(port, status.asIntBuffer());
047        HALUtil.checkStatus(status.asIntBuffer());
048
049        LiveWindow.addActuator("Solenoid", m_moduleNumber, m_channel, this);
050        UsageReporting.report(tResourceType.kResourceType_Solenoid, m_channel, m_moduleNumber);
051    }
052
053    /**
054     * Constructor using the default PCM ID (0)
055     *
056     * @param channel The channel on the PCM to control (0..7).
057     */
058    public Solenoid(final int channel) {
059        super(getDefaultSolenoidModule());
060        m_channel = channel;
061        initSolenoid();
062    }
063
064    /**
065     * Constructor.
066     *
067     * @param moduleNumber The CAN ID of the PCM the solenoid is attached to.
068     * @param channel The channel on the PCM to control (0..7).
069     */
070    public Solenoid(final int moduleNumber, final int channel) {
071        super(moduleNumber);
072        m_channel = channel;
073        initSolenoid();
074    }
075
076    /**
077     * Destructor.
078     */
079    public synchronized void free() {
080  //      m_allocated.free((m_moduleNumber - 1) * kSolenoidChannels + m_channel - 1);
081    }
082
083    /**
084     * Set the value of a solenoid.
085     *
086     * @param on Turn the solenoid output off or on.
087     */
088    public void set(boolean on) {
089        byte value = (byte) (on ? 0xFF : 0x00);
090        byte mask = (byte) (1 << m_channel);
091
092        set(value, mask);
093    }
094
095    /**
096     * Read the current value of the solenoid.
097     *
098     * @return The current value of the solenoid.
099     */
100    public boolean get() {
101        int value = getAll() & ( 1 << m_channel);
102        return (value != 0);
103    }
104        /**
105         * Check if solenoid is blacklisted.
106         *              If a solenoid is shorted, it is added to the blacklist and
107         *              disabled until power cycle, or until faults are cleared.
108         *              @see clearAllPCMStickyFaults()
109         *
110         * @return If solenoid is disabled due to short.
111         */
112        public boolean isBlackListed() {
113                int value = getPCMSolenoidBlackList() & ( 1 << m_channel);
114                return (value != 0);
115        }
116    /*
117     * Live Window code, only does anything if live window is activated.
118     */
119    public String getSmartDashboardType() {
120        return "Solenoid";
121    }
122    private ITable m_table;
123    private ITableListener m_table_listener;
124
125    /**
126     * {@inheritDoc}
127     */
128    public void initTable(ITable subtable) {
129        m_table = subtable;
130        updateTable();
131    }
132
133    /**
134     * {@inheritDoc}
135     */
136    public ITable getTable() {
137        return m_table;
138    }
139
140    /**
141     * {@inheritDoc}
142     */
143    public void updateTable() {
144        if (m_table != null) {
145            m_table.putBoolean("Value", get());
146        }
147    }
148
149
150    /**
151     * {@inheritDoc}
152     */
153    public void startLiveWindowMode() {
154        set(false); // Stop for safety
155        m_table_listener = new ITableListener() {
156            public void valueChanged(ITable itable, String key, Object value, boolean bln) {
157                set(((Boolean) value).booleanValue());
158            }
159        };
160        m_table.addTableListener("Value", m_table_listener, true);
161    }
162
163    /**
164     * {@inheritDoc}
165     */
166    public void stopLiveWindowMode() {
167        set(false); // Stop for safety
168        // TODO: Broken, should only remove the listener from "Value" only.
169        m_table.removeTableListener(m_table_listener);
170    }
171}