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