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.wpilibj; 006 007import edu.wpi.first.hal.util.AllocationException; 008import edu.wpi.first.util.sendable.Sendable; 009import edu.wpi.first.util.sendable.SendableBuilder; 010import edu.wpi.first.util.sendable.SendableRegistry; 011 012/** 013 * Solenoid class for running high voltage Digital Output on a pneumatics module. 014 * 015 * <p>The Solenoid class is typically used for pneumatic solenoids, but could be used for any device 016 * within the current spec of the module. 017 */ 018public class Solenoid implements Sendable, AutoCloseable { 019 private final int m_mask; // The channel mask 020 private final int m_channel; 021 private PneumaticsBase m_module; 022 023 /** 024 * Constructs a solenoid for a default module and specified type. 025 * 026 * @param busId The bus ID 027 * @param moduleType The module type to use. 028 * @param channel The channel the solenoid is on. 029 */ 030 public Solenoid(final int busId, final PneumaticsModuleType moduleType, final int channel) { 031 this(busId, PneumaticsBase.getDefaultForType(moduleType), moduleType, channel); 032 } 033 034 /** 035 * Constructs a solenoid for a specified module and type. 036 * 037 * @param busId The bus ID 038 * @param module The module ID to use. 039 * @param moduleType The module type to use. 040 * @param channel The channel the solenoid is on. 041 */ 042 @SuppressWarnings("this-escape") 043 public Solenoid( 044 final int busId, final int module, final PneumaticsModuleType moduleType, final int channel) { 045 m_module = PneumaticsBase.getForType(busId, module, moduleType); 046 047 m_mask = 1 << channel; 048 m_channel = channel; 049 050 if (!m_module.checkSolenoidChannel(channel)) { 051 m_module.close(); 052 throw new IllegalArgumentException("Channel " + channel + " out of range"); 053 } 054 055 if (m_module.checkAndReserveSolenoids(m_mask) != 0) { 056 m_module.close(); 057 throw new AllocationException("Solenoid already allocated"); 058 } 059 060 m_module.reportUsage("Solenoid[" + channel + "]", "Solenoid"); 061 SendableRegistry.add(this, "Solenoid", m_module.getModuleNumber(), channel); 062 } 063 064 @Override 065 public void close() { 066 SendableRegistry.remove(this); 067 m_module.unreserveSolenoids(m_mask); 068 m_module.close(); 069 m_module = null; 070 } 071 072 /** 073 * Set the value of a solenoid. 074 * 075 * @param on True will turn the solenoid output on. False will turn the solenoid output off. 076 */ 077 public void set(boolean on) { 078 int value = on ? (0xFFFF & m_mask) : 0; 079 m_module.setSolenoids(m_mask, value); 080 } 081 082 /** 083 * Read the current value of the solenoid. 084 * 085 * @return True if the solenoid output is on or false if the solenoid output is off. 086 */ 087 public boolean get() { 088 int currentAll = m_module.getSolenoids(); 089 return (currentAll & m_mask) != 0; 090 } 091 092 /** 093 * Toggle the value of the solenoid. 094 * 095 * <p>If the solenoid is set to on, it'll be turned off. If the solenoid is set to off, it'll be 096 * turned on. 097 */ 098 public void toggle() { 099 set(!get()); 100 } 101 102 /** 103 * Get the channel this solenoid is connected to. 104 * 105 * @return The channel this solenoid is connected to. 106 */ 107 public int getChannel() { 108 return m_channel; 109 } 110 111 /** 112 * Check if solenoid is DisabledListed. If a solenoid is shorted, it is added to the Disabled List 113 * and disabled until power cycle, or until faults are cleared. 114 * 115 * @return If solenoid is disabled due to short. 116 */ 117 public boolean isDisabled() { 118 return (m_module.getSolenoidDisabledList() & m_mask) != 0; 119 } 120 121 /** 122 * Set the pulse duration in the pneumatics module. This is used in conjunction with the 123 * startPulse method to allow the pneumatics module to control the timing of a pulse. 124 * 125 * <p>On the PCM, the timing can be controlled in 0.01 second increments, with a maximum of 2.55 126 * seconds. 127 * 128 * <p>On the PH, the timing can be controlled in 0.001 second increments, with a maximum of 65.534 129 * seconds. 130 * 131 * @param duration The duration of the pulse in seconds. 132 * @see #startPulse() 133 */ 134 public void setPulseDuration(double duration) { 135 long durationMS = (long) (duration * 1000); 136 m_module.setOneShotDuration(m_channel, (int) durationMS); 137 } 138 139 /** 140 * Trigger the pneumatics module to generate a pulse of the duration set in setPulseDuration. 141 * 142 * @see #setPulseDuration(double) 143 */ 144 public void startPulse() { 145 m_module.fireOneShot(m_channel); 146 } 147 148 @Override 149 public void initSendable(SendableBuilder builder) { 150 builder.setSmartDashboardType("Solenoid"); 151 builder.setActuator(true); 152 builder.addBooleanProperty("Value", this::get, this::set); 153 } 154}