001/*----------------------------------------------------------------------------*/ 002/* Copyright (c) 2008-2018 FIRST. 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.DIOJNI; 011import edu.wpi.first.wpilibj.hal.FRCNetComm.tResourceType; 012import edu.wpi.first.wpilibj.hal.HAL; 013import edu.wpi.first.wpilibj.smartdashboard.SendableBuilder; 014 015/** 016 * Class to write digital outputs. This class will write digital outputs. Other devices that are 017 * implemented elsewhere will automatically allocate digital inputs and outputs as required. 018 */ 019public class DigitalOutput extends SendableBase implements Sendable { 020 private static final int invalidPwmGenerator = 0; 021 private int m_pwmGenerator = invalidPwmGenerator; 022 023 private int m_channel = 0; 024 private int m_handle = 0; 025 026 /** 027 * Create an instance of a digital output. Create an instance of a digital output given a 028 * channel. 029 * 030 * @param channel the DIO channel to use for the digital output. 0-9 are on-board, 10-25 are on 031 * the MXP 032 */ 033 public DigitalOutput(int channel) { 034 SensorBase.checkDigitalChannel(channel); 035 m_channel = channel; 036 037 m_handle = DIOJNI.initializeDIOPort(DIOJNI.getPort((byte) channel), false); 038 039 HAL.report(tResourceType.kResourceType_DigitalOutput, channel); 040 setName("DigitalOutput", channel); 041 } 042 043 /** 044 * Free the resources associated with a digital output. 045 */ 046 @Override 047 public void free() { 048 super.free(); 049 // disable the pwm only if we have allocated it 050 if (m_pwmGenerator != invalidPwmGenerator) { 051 disablePWM(); 052 } 053 DIOJNI.freeDIOPort(m_handle); 054 m_handle = 0; 055 } 056 057 /** 058 * Set the value of a digital output. 059 * 060 * @param value true is on, off is false 061 */ 062 public void set(boolean value) { 063 DIOJNI.setDIO(m_handle, (short) (value ? 1 : 0)); 064 } 065 066 /** 067 * Gets the value being output from the Digital Output. 068 * 069 * @return the state of the digital output. 070 */ 071 public boolean get() { 072 return DIOJNI.getDIO(m_handle); 073 } 074 075 /** 076 * Get the GPIO channel number that this object represents. 077 * 078 * @return The GPIO channel number. 079 */ 080 public int getChannel() { 081 return m_channel; 082 } 083 084 /** 085 * Generate a single pulse. There can only be a single pulse going at any time. 086 * 087 * @param pulseLength The length of the pulse. 088 */ 089 public void pulse(final double pulseLength) { 090 DIOJNI.pulse(m_handle, pulseLength); 091 } 092 093 /** 094 * Determine if the pulse is still going. Determine if a previously started pulse is still going. 095 * 096 * @return true if pulsing 097 */ 098 public boolean isPulsing() { 099 return DIOJNI.isPulsing(m_handle); 100 } 101 102 /** 103 * Change the PWM frequency of the PWM output on a Digital Output line. 104 * 105 * <p>The valid range is from 0.6 Hz to 19 kHz. The frequency resolution is logarithmic. 106 * 107 * <p>There is only one PWM frequency for all channels. 108 * 109 * @param rate The frequency to output all digital output PWM signals. 110 */ 111 public void setPWMRate(double rate) { 112 DIOJNI.setDigitalPWMRate(rate); 113 } 114 115 /** 116 * Enable a PWM Output on this line. 117 * 118 * <p>Allocate one of the 6 DO PWM generator resources. 119 * 120 * <p>Supply the initial duty-cycle to output so as to avoid a glitch when first starting. 121 * 122 * <p>The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less) but is reduced 123 * the higher the frequency of the PWM signal is. 124 * 125 * @param initialDutyCycle The duty-cycle to start generating. [0..1] 126 */ 127 public void enablePWM(double initialDutyCycle) { 128 if (m_pwmGenerator != invalidPwmGenerator) { 129 return; 130 } 131 m_pwmGenerator = DIOJNI.allocateDigitalPWM(); 132 DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, initialDutyCycle); 133 DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, m_channel); 134 } 135 136 /** 137 * Change this line from a PWM output back to a static Digital Output line. 138 * 139 * <p>Free up one of the 6 DO PWM generator resources that were in use. 140 */ 141 public void disablePWM() { 142 if (m_pwmGenerator == invalidPwmGenerator) { 143 return; 144 } 145 // Disable the output by routing to a dead bit. 146 DIOJNI.setDigitalPWMOutputChannel(m_pwmGenerator, SensorBase.kDigitalChannels); 147 DIOJNI.freeDigitalPWM(m_pwmGenerator); 148 m_pwmGenerator = invalidPwmGenerator; 149 } 150 151 /** 152 * Change the duty-cycle that is being generated on the line. 153 * 154 * <p>The resolution of the duty cycle is 8-bit for low frequencies (1kHz or less) but is reduced 155 * the 156 * higher the frequency of the PWM signal is. 157 * 158 * @param dutyCycle The duty-cycle to change to. [0..1] 159 */ 160 public void updateDutyCycle(double dutyCycle) { 161 if (m_pwmGenerator == invalidPwmGenerator) { 162 return; 163 } 164 DIOJNI.setDigitalPWMDutyCycle(m_pwmGenerator, dutyCycle); 165 } 166 167 @Override 168 public void initSendable(SendableBuilder builder) { 169 builder.setSmartDashboardType("Digital Output"); 170 builder.addBooleanProperty("Value", this::get, this::set); 171 } 172}