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 public Solenoid(final int module, final PneumaticsModuleType moduleType, final int channel) { 043 m_module = PneumaticsBase.getForType(module, moduleType); 044 045 m_mask = 1 << channel; 046 m_channel = channel; 047 048 if (!m_module.checkSolenoidChannel(channel)) { 049 m_module.close(); 050 throw new IllegalArgumentException("Channel " + channel + " out of range"); 051 } 052 053 if (m_module.checkAndReserveSolenoids(m_mask) != 0) { 054 m_module.close(); 055 throw new AllocationException("Solenoid already allocated"); 056 } 057 058 HAL.report(tResourceType.kResourceType_Solenoid, channel + 1, m_module.getModuleNumber() + 1); 059 SendableRegistry.addLW(this, "Solenoid", m_module.getModuleNumber(), channel); 060 } 061 062 @Override 063 public void close() { 064 SendableRegistry.remove(this); 065 m_module.unreserveSolenoids(m_mask); 066 m_module.close(); 067 m_module = null; 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 int value = on ? (0xFFFF & m_mask) : 0; 077 m_module.setSolenoids(m_mask, value); 078 } 079 080 /** 081 * Read the current value of the solenoid. 082 * 083 * @return True if the solenoid output is on or false if the solenoid output is off. 084 */ 085 public boolean get() { 086 int currentAll = m_module.getSolenoids(); 087 return (currentAll & m_mask) != 0; 088 } 089 090 /** 091 * Toggle the value of the solenoid. 092 * 093 * <p>If the solenoid is set to on, it'll be turned off. If the solenoid is set to off, it'll be 094 * turned on. 095 */ 096 public void toggle() { 097 set(!get()); 098 } 099 100 /** 101 * Get the channel this solenoid is connected to. 102 * 103 * @return The channel this solenoid is connected to. 104 */ 105 public int getChannel() { 106 return m_channel; 107 } 108 109 /** 110 * Check if solenoid is DisabledListed. If a solenoid is shorted, it is added to the Disabled List 111 * and disabled until power cycle, or until faults are cleared. 112 * 113 * @return If solenoid is disabled due to short. 114 */ 115 public boolean isDisabled() { 116 return (m_module.getSolenoidDisabledList() & m_mask) != 0; 117 } 118 119 /** 120 * Set the pulse duration in the pneumatics module. This is used in conjunction with the 121 * startPulse method to allow the pneumatics module to control the timing of a pulse. 122 * 123 * <p>On the PCM, the timing can be controlled in 0.01 second increments, with a maximum of 2.55 124 * seconds. 125 * 126 * <p>On the PH, the timing can be controlled in 0.001 second increments, with a maximum of 65.534 127 * seconds. 128 * 129 * @param durationSeconds The duration of the pulse in seconds. 130 * @see #startPulse() 131 */ 132 public void setPulseDuration(double durationSeconds) { 133 long durationMS = (long) (durationSeconds * 1000); 134 m_module.setOneShotDuration(m_channel, (int) durationMS); 135 } 136 137 /** 138 * Trigger the pneumatics module to generate a pulse of the duration set in setPulseDuration. 139 * 140 * @see #setPulseDuration(double) 141 */ 142 public void startPulse() { 143 m_module.fireOneShot(m_channel); 144 } 145 146 @Override 147 public void initSendable(SendableBuilder builder) { 148 builder.setSmartDashboardType("Solenoid"); 149 builder.setActuator(true); 150 builder.setSafeState(() -> set(false)); 151 builder.addBooleanProperty("Value", this::get, this::set); 152 } 153}