/*----------------------------------------------------------------------------*/ /* Copyright (c) FIRST 2008. All Rights Reserved. */ /* Open Source Software - may be modified and shared by FRC teams. The code */ /* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */ /*----------------------------------------------------------------------------*/ #include "DriverStationEnhancedIO.h" //#include "NetworkCommunication/UsageReporting.h" #include "HAL/cpp/Synchronized.hpp" #include "WPIErrors.h" #include /** * DriverStationEnhancedIO contructor. * * This is only called once when the DriverStation constructor is called. */ DriverStationEnhancedIO::DriverStationEnhancedIO() : m_inputValid (false) , m_outputValid (false) , m_configChanged (false) , m_requestEnhancedEnable (false) { bzero((char*)&m_inputData, sizeof(m_inputData)); bzero((char*)&m_outputData, sizeof(m_outputData)); m_outputData.size = sizeof(m_outputData) - 1; m_outputData.id = kOutputBlockID; // Expected to be active low, so initialize inactive. m_outputData.data.fixed_digital_out = 0x3; m_inputDataSemaphore = initializeMutexNormal(); m_outputDataSemaphore = initializeMutexNormal(); m_encoderOffsets[0] = 0; m_encoderOffsets[1] = 0; } /** * DriverStationEnhancedIO destructor. * * Called only when the DriverStation class is destroyed. */ DriverStationEnhancedIO::~DriverStationEnhancedIO() { deleteMutex(m_outputDataSemaphore); deleteMutex(m_inputDataSemaphore); } /** * Called by the DriverStation class when data is available. * This function will set any modified configuration / output, * then read the input and configuration from the IO. */ void DriverStationEnhancedIO::UpdateData() { int32_t retVal; { status_block_t tempOutputData; Synchronized sync(m_outputDataSemaphore); if (m_outputValid || m_configChanged || m_requestEnhancedEnable) { m_outputData.flags = kStatusValid; if (m_requestEnhancedEnable) { // Someone called one of the get config APIs, but we are not in enhanced mode. m_outputData.flags |= kForceEnhancedMode; } if (m_configChanged) { if (!m_outputValid) { // Someone called one of the set config APIs, but we are not in enhanced mode. m_outputData.flags |= kForceEnhancedMode; } m_outputData.flags |= kStatusConfigChanged; } HALOverrideIOConfig((char*)&m_outputData, 5); } retVal = HALGetDynamicControlData(kOutputBlockID, (char*)&tempOutputData, sizeof(status_block_t), 5); if (retVal == 0) { if (m_outputValid) { if (m_configChanged) { // If our config change made the round trip then clear the flag. if (IsConfigEqual(tempOutputData, m_outputData)) { m_configChanged = false; } } else { // TODO: This won't work until artf1128 is fixed //if (tempOutputData.flags & kStatusConfigChanged) { // Configuration was updated on the DS, so update our local cache. MergeConfigIntoOutput(tempOutputData, m_outputData); } } } else { // Initialize the local cache. MergeConfigIntoOutput(tempOutputData, m_outputData); } m_requestEnhancedEnable = false; m_outputValid = true; } else { m_outputValid = false; m_inputValid = false; } } { Synchronized sync(m_inputDataSemaphore); control_block_t tempInputData; retVal = HALGetDynamicControlData(kInputBlockID, (char*)&tempInputData, sizeof(control_block_t), 5); if (retVal == 0 && tempInputData.data.api_version == kSupportedAPIVersion) { m_inputData = tempInputData; m_inputValid = true; } else { m_outputValid = false; m_inputValid = false; } } } /** * Merge the config portion of the DS output block into the local cache. */ void DriverStationEnhancedIO::MergeConfigIntoOutput(const status_block_t &dsOutputBlock, status_block_t &localCache) { localCache.data.digital = (localCache.data.digital & dsOutputBlock.data.digital_oe) | (dsOutputBlock.data.digital & ~dsOutputBlock.data.digital_oe); localCache.data.digital_oe = dsOutputBlock.data.digital_oe; localCache.data.digital_pe = dsOutputBlock.data.digital_pe; localCache.data.pwm_period[0] = dsOutputBlock.data.pwm_period[0]; localCache.data.pwm_period[1] = dsOutputBlock.data.pwm_period[1]; localCache.data.enables = dsOutputBlock.data.enables; } /** * Compare the config portion of the output blocks. */ bool DriverStationEnhancedIO::IsConfigEqual(const status_block_t &dsOutputBlock, const status_block_t &localCache) { if (localCache.data.digital_oe != dsOutputBlock.data.digital_oe) return false; if ((localCache.data.digital & ~dsOutputBlock.data.digital) != (dsOutputBlock.data.digital & ~dsOutputBlock.data.digital)) return false; if (localCache.data.digital_pe != dsOutputBlock.data.digital_pe) return false; if (localCache.data.pwm_period[0] != dsOutputBlock.data.pwm_period[0]) return false; if (localCache.data.pwm_period[1] != dsOutputBlock.data.pwm_period[1]) return false; if (localCache.data.enables != dsOutputBlock.data.enables) return false; return true; } /** * Query an accelerometer channel on the DS IO. * * @param channel The channel number to read. * @return The current acceleration on the channel in Gs. */ double DriverStationEnhancedIO::GetAcceleration(tAccelChannel channel) { if (channel < 1 || channel > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 2"); return 0.0; } if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0.0; } static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_Acceleration); reported_mask |= (1 >> channel); } Synchronized sync(m_inputDataSemaphore); return (m_inputData.data.accel[channel] - kAccelOffset) / kAccelScale; } /** * Query an analog input channel on the DS IO. * * @param channel The channel number to read. [1,8] * @return The analog input voltage for the channel. */ double DriverStationEnhancedIO::GetAnalogIn(uint32_t channel) { // 3.3V is the analog reference voltage return GetAnalogInRatio(channel) * kAnalogInputReference; } /** * Query an analog input channel on the DS IO in ratiometric form. * * @param channel The channel number to read. [1,8] * @return The analog input percentage for the channel. */ double DriverStationEnhancedIO::GetAnalogInRatio(uint32_t channel) { if (channel < 1 || channel > 8) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 8"); return 0.0; } if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0.0; } static uint16_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_AnalogIn); reported_mask |= (1 >> channel); } Synchronized sync(m_inputDataSemaphore); return m_inputData.data.analog[channel-1] / kAnalogInputResolution; } /** * Query the voltage currently being output. * * AO1 is pin 11 on the top connector (P2). * AO2 is pin 12 on the top connector (P2). * * @param channel The analog output channel on the DS IO. [1,2] * @return The voltage being output on the channel. */ double DriverStationEnhancedIO::GetAnalogOut(uint32_t channel) { if (channel < 1 || channel > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 2"); return 0.0; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return 0.0; } Synchronized sync(m_outputDataSemaphore); return m_outputData.data.dac[channel-1] * kAnalogOutputReference / kAnalogOutputResolution; } /** * Set the analog output voltage. * * AO1 is pin 11 on the top connector (P2). * AO2 is pin 12 on the top connector (P2). * AO1 is the reference voltage for the 2 analog comparators on DIO15 and DIO16. * * The output range is 0V to 4V, however due to the supply voltage don't expect more than about 3V. * Current supply capability is only 100uA. * * @param channel The analog output channel on the DS IO. [1,2] * @param value The voltage to output on the channel. */ void DriverStationEnhancedIO::SetAnalogOut(uint32_t channel, double value) { if (channel < 1 || channel > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 2"); return; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } if (value < 0.0) value = 0.0; if (value > kAnalogOutputReference) value = kAnalogOutputReference; static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_AnalogOut); reported_mask |= (1 >> channel); } Synchronized sync(m_outputDataSemaphore); m_outputData.data.dac[channel-1] = (uint8_t)(value / kAnalogOutputReference * kAnalogOutputResolution); } /** * Get the state of a button on the IO board. * * Button1 is the physical button "S1". * Button2 is pin 4 on the top connector (P2). * Button3 is pin 6 on the top connector (P2). * Button4 is pin 8 on the top connector (P2). * Button5 is pin 10 on the top connector (P2). * Button6 is pin 7 on the top connector (P2). * * Button2 through Button6 are Capacitive Sense buttons. * * @param channel The button channel to read. [1,6] * @return The state of the selected button. */ bool DriverStationEnhancedIO::GetButton(uint32_t channel) { if (channel < 1 || channel > 6) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 6"); return false; } static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_Button); reported_mask |= (1 >> channel); } return ((GetButtons() >> (channel-1)) & 1) != 0; } /** * Get the state of all the button channels. * * @return The state of the 6 button channels in the 6 lsb of the returned byte. */ uint8_t DriverStationEnhancedIO::GetButtons() { if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0; } HALReport(HALUsageReporting::kResourceType_DriverStationEIO, 0, HALUsageReporting::kDriverStationEIO_Button); Synchronized sync(m_inputDataSemaphore); return m_inputData.data.buttons; } /** * Set the state of an LED on the IO board. * * @param channel The LED channel to set. [1,8] * @param value True to turn the LED on. */ void DriverStationEnhancedIO::SetLED(uint32_t channel, bool value) { if (channel < 1 || channel > 8) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 8"); return; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } static uint16_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_LED); reported_mask |= (1 >> channel); } uint8_t leds; Synchronized sync(m_outputDataSemaphore); leds = m_outputData.data.leds; leds &= ~(1 << (channel-1)); if (value) leds |= 1 << (channel-1); m_outputData.data.leds = leds; } /** * Set the state of all 8 LEDs on the IO board. * * @param value The state of each LED. LED1 is lsb and LED8 is msb. */ void DriverStationEnhancedIO::SetLEDs(uint8_t value) { if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } HALReport(HALUsageReporting::kResourceType_DriverStationEIO, 0, HALUsageReporting::kDriverStationEIO_LED); Synchronized sync(m_outputDataSemaphore); m_outputData.data.leds = value; } /** * Get the current state of a DIO channel regardless of mode. * * @param channel The DIO channel to read. [1,16] * @return The state of the selected digital line. */ bool DriverStationEnhancedIO::GetDigital(uint32_t channel) { if (channel < 1 || channel > 16) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 16"); return false; } static uint32_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_DigitalIn); reported_mask |= (1 >> channel); } return ((GetDigitals() >> (channel-1)) & 1) != 0; } /** * Get the state of all 16 DIO lines regardless of mode. * * @return The state of all DIO lines. DIO1 is lsb and DIO16 is msb. */ uint16_t DriverStationEnhancedIO::GetDigitals() { if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0; } HALReport(HALUsageReporting::kResourceType_DriverStationEIO, 0, HALUsageReporting::kDriverStationEIO_DigitalIn); Synchronized sync(m_inputDataSemaphore); return m_inputData.data.digital; } /** * Set the state of a DIO line that is configured for digital output. * * @param channel The DIO channel to set. [1,16] * @param value The state to set the selected channel to. */ void DriverStationEnhancedIO::SetDigitalOutput(uint32_t channel, bool value) { if (channel < 1 || channel > 16) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 16"); return; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } static uint32_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_DigitalOut); reported_mask |= (1 >> channel); } uint16_t digital; Synchronized sync(m_outputDataSemaphore); if (m_outputData.data.digital_oe & (1 << (channel-1))) { digital = m_outputData.data.digital; digital &= ~(1 << (channel-1)); if (value) digital |= 1 << (channel-1); m_outputData.data.digital = digital; } else { wpi_setWPIError(LineNotOutput); } } /** * Get the current configuration for a DIO line. * * This has the side effect of forcing the Driver Station to switch to Enhanced mode if it's not when called. * If Enhanced mode is not enabled when this is called, it will return kUnknown. * * @param channel The DIO channel config to get. [1,16] * @return The configured mode for the DIO line. */ DriverStationEnhancedIO::tDigitalConfig DriverStationEnhancedIO::GetDigitalConfig(uint32_t channel) { if (channel < 1 || channel > 16) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 16"); return kUnknown; } if (!m_outputValid) { m_requestEnhancedEnable = true; wpi_setWPIError(EnhancedIOMissing); return kUnknown; } Synchronized sync(m_outputDataSemaphore); if ((channel >= 1) && (channel <= 4)) { if (m_outputData.data.pwm_enable & (1 << (channel - 1))) { return kPWM; } } if ((channel >= 15) && (channel <= 16)) { if (m_outputData.data.comparator_enable & (1 << (channel - 15))) { return kAnalogComparator; } } if (m_outputData.data.digital_oe & (1 << (channel - 1))) { return kOutput; } if (!(m_outputData.data.digital_pe & (1 << (channel - 1)))) { return kInputFloating; } if (m_outputData.data.digital & (1 << (channel - 1))) { return kInputPullUp; } else { return kInputPullDown; } } /** * Override the DS's configuration of a DIO line. * * If configured to kInputFloating, the selected DIO line will be tri-stated with no internal pull resistor. * * If configured to kInputPullUp, the selected DIO line will be tri-stated with a 5k-Ohm internal pull-up resistor enabled. * * If configured to kInputPullDown, the selected DIO line will be tri-stated with a 5k-Ohm internal pull-down resistor enabled. * * If configured to kOutput, the selected DIO line will actively drive to 0V or Vddio (specified by J1 and J4). * DIO1 through DIO12, DIO15, and DIO16 can source 4mA and can sink 8mA. * DIO12 and DIO13 can source 4mA and can sink 25mA. * * In addition to the common configurations, DIO1 through DIO4 can be configured to kPWM to enable PWM output. * * In addition to the common configurations, DIO15 and DIO16 can be configured to kAnalogComparator to enable * analog comparators on those 2 DIO lines. When enabled, the lines are tri-stated and will accept analog voltages * between 0V and 3.3V. If the input voltage is greater than the voltage output by AO1, the DIO will read as true, * if less then false. * * @param channel The DIO line to configure. [1,16] * @param config The mode to put the DIO line in. */ void DriverStationEnhancedIO::SetDigitalConfig(uint32_t channel, tDigitalConfig config) { if (channel < 1 || channel > 16) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 16"); return; } if (config == kPWM && (channel < 1 || channel > 4)) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel in PWM mode must be between 1 and 4"); return; } if (config == kAnalogComparator && (channel < 15 || channel > 16)) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel in Analog Comparator mode must be between 15 and 16"); return; } Synchronized sync(m_outputDataSemaphore); m_configChanged = true; if ((channel >= 1) && (channel <= 4)) { if (config == kPWM) { m_outputData.data.pwm_enable |= 1 << (channel - 1); m_outputData.data.digital &= ~(1 << (channel - 1)); m_outputData.data.digital_oe |= 1 << (channel - 1); m_outputData.data.digital_pe &= ~(1 << (channel - 1)); return; } else { m_outputData.data.pwm_enable &= ~(1 << (channel - 1)); } } else if ((channel >= 15) && (channel <= 16)) { if (config == kAnalogComparator) { m_outputData.data.comparator_enable |= 1 << (channel - 15); m_outputData.data.digital &= ~(1 << (channel - 1)); m_outputData.data.digital_oe &= ~(1 << (channel - 1)); m_outputData.data.digital_pe &= ~(1 << (channel - 1)); return; } else { m_outputData.data.comparator_enable &= ~(1 << (channel - 15)); } } if (config == kInputFloating) { m_outputData.data.digital &= ~(1 << (channel - 1)); m_outputData.data.digital_oe &= ~(1 << (channel - 1)); m_outputData.data.digital_pe &= ~(1 << (channel - 1)); } else if (config == kInputPullUp) { m_outputData.data.digital |= 1 << (channel - 1); m_outputData.data.digital_oe &= ~(1 << (channel - 1)); m_outputData.data.digital_pe |= 1 << (channel - 1); } else if (config == kInputPullDown) { m_outputData.data.digital &= ~(1 << (channel - 1)); m_outputData.data.digital_oe &= ~(1 << (channel - 1)); m_outputData.data.digital_pe |= 1 << (channel - 1); } else if (config == kOutput) { m_outputData.data.digital_oe |= 1 << (channel - 1); m_outputData.data.digital_pe &= ~(1 << (channel - 1)); } else { // Something went wrong. } } /** * Get the period of a PWM generator. * * This has the side effect of forcing the Driver Station to switch to Enhanced mode if it's not when called. * If Enhanced mode is not enabled when this is called, it will return 0. * * @param channels Select the generator by specifying the two channels to which it is connected. * @return The period of the PWM generator in seconds. */ double DriverStationEnhancedIO::GetPWMPeriod(tPWMPeriodChannels channels) { if (channels < kPWMChannels1and2 || channels > kPWMChannels3and4) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channels must be kPWMChannels1and2 or kPWMChannels3and4"); return 0.0; } if (!m_outputValid) { m_requestEnhancedEnable = true; wpi_setWPIError(EnhancedIOMissing); return 0.0; } Synchronized sync(m_outputDataSemaphore); return m_outputData.data.pwm_period[channels] / 24000000.0; } /** * Set the period of a PWM generator. * * There are 2 PWM generators on the IO board. One can generate PWM signals on DIO1 and DIO2, * the other on DIO3 and DIO4. Each generator has one counter and two compare registers. As such, * each pair of PWM outputs share the output period but have independent duty cycles. * * @param channels Select the generator by specifying the two channels to which it is connected. * @param period The period of the PWM generator in seconds. [0.0,0.002731] */ void DriverStationEnhancedIO::SetPWMPeriod(tPWMPeriodChannels channels, double period) { if (channels < kPWMChannels1and2 || channels > kPWMChannels3and4) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channels must be kPWMChannels1and2 or kPWMChannels3and4"); return; } // Convert to ticks based on the IO board's 24MHz clock double ticks = period * 24000000.0; // Limit the range of the ticks... warn if too big. if (ticks > 65534.0) { wpi_setWPIError(EnhancedIOPWMPeriodOutOfRange); ticks = 65534.0; } else if (ticks < 0.0) ticks = 0.0; // Preserve the duty cycles. double dutyCycles[2]; dutyCycles[0] = GetPWMOutput((channels << 1) + 1); dutyCycles[1] = GetPWMOutput((channels << 1) + 2); { Synchronized sync(m_outputDataSemaphore); // Update the period m_outputData.data.pwm_period[channels] = (uint16_t)ticks; m_configChanged = true; } // Restore the duty cycles SetPWMOutput((channels << 1) + 1, dutyCycles[0]); SetPWMOutput((channels << 1) + 2, dutyCycles[1]); } /** * Get the state being output on a fixed digital output. * * @param channel The FixedDO line to get. [1,2] * @return The state of the FixedDO line. */ bool DriverStationEnhancedIO::GetFixedDigitalOutput(uint32_t channel) { if (channel < 1 || channel > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 2"); return 0; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return 0; } Synchronized sync(m_outputDataSemaphore); return ((m_outputData.data.fixed_digital_out >> (channel-1)) & 1) != 0; } /** * Set the state to output on a Fixed High Current Digital Output line. * * FixedDO1 is pin 5 on the top connector (P2). * FixedDO2 is pin 3 on the top connector (P2). * * The FixedDO lines always output 0V and 3.3V regardless of J1 and J4. * They can source 4mA and can sink 25mA. Because of this, they are expected to be used * in an active low configuration, such as connecting to the cathode of a bright LED. * Because they are expected to be active low, they default to true. * * @param channel The FixedDO channel to set. * @param value The state to set the FixedDO. */ void DriverStationEnhancedIO::SetFixedDigitalOutput(uint32_t channel, bool value) { if (channel < 1 || channel > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 2"); return; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_FixedDigitalOut); reported_mask |= (1 >> channel); } uint8_t digital; Synchronized sync(m_outputDataSemaphore); digital = m_outputData.data.fixed_digital_out; digital &= ~(1 << (channel-1)); if (value) digital |= 1 << (channel-1); m_outputData.data.fixed_digital_out = digital; } /** * Get the position of a quadrature encoder. * * There are two signed 16-bit 4X quadrature decoders on the IO board. These decoders are always monitoring * the state of the lines assigned to them, but these lines do not have to be used for encoders. * * Encoder1 uses DIO4 for "A", DIO6 for "B", and DIO8 for "Index". * Encoder2 uses DIO5 for "A", DIO7 for "B", and DIO9 for "Index". * * The index functionality can be enabled or disabled using SetEncoderIndexEnable(). * * @param encoderNumber The quadrature encoder to access. [1,2] * @return The current position of the quadrature encoder. */ int16_t DriverStationEnhancedIO::GetEncoder(uint32_t encoderNumber) { if (encoderNumber < 1 || encoderNumber > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "encoderNumber must be between 1 and 2"); return 0; } if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0; } static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> encoderNumber))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, encoderNumber, HALUsageReporting::kDriverStationEIO_Encoder); reported_mask |= (1 >> encoderNumber); } Synchronized sync(m_inputDataSemaphore); return m_inputData.data.quad[encoderNumber - 1] - m_encoderOffsets[encoderNumber - 1]; } /** * Reset the position of an encoder to 0. * * This simply stores an offset locally. It does not reset the hardware counter on the IO board. * If you use this method with Index enabled, you may get unexpected results. * * @param encoderNumber The quadrature encoder to reset. [1,2] */ void DriverStationEnhancedIO::ResetEncoder(uint32_t encoderNumber) { if (encoderNumber < 1 || encoderNumber > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "encoderNumber must be between 1 and 2"); return; } if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return; } Synchronized sync(m_inputDataSemaphore); m_encoderOffsets[encoderNumber - 1] = m_inputData.data.quad[encoderNumber - 1]; } /** * Get the current configuration of a quadrature encoder index channel. * * This has the side effect of forcing the Driver Station to switch to Enhanced mode if it's not when called. * If Enhanced mode is not enabled when this is called, it will return false. * * @param encoderNumber The quadrature encoder. [1,2] * @return Is the index channel of the encoder enabled. */ bool DriverStationEnhancedIO::GetEncoderIndexEnable(uint32_t encoderNumber) { if (encoderNumber < 1 || encoderNumber > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "encoderNumber must be between 1 and 2"); return false; } if (!m_outputValid) { m_requestEnhancedEnable = true; wpi_setWPIError(EnhancedIOMissing); return false; } Synchronized sync(m_outputDataSemaphore); return ((m_outputData.data.quad_index_enable >> (encoderNumber - 1)) & 1) != 0; } /** * Enable or disable the index channel of a quadrature encoder. * * The quadrature decoders on the IO board support an active-low index input. * * Encoder1 uses DIO8 for "Index". * Encoder2 uses DIO9 for "Index". * * When enabled, the decoder's counter will be reset to 0 when A, B, and Index are all low. * * @param encoderNumber The quadrature encoder. [1,2] * @param enable If true, reset the encoder in an index condition. */ void DriverStationEnhancedIO::SetEncoderIndexEnable(uint32_t encoderNumber, bool enable) { if (encoderNumber < 1 || encoderNumber > 2) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "encoderNumber must be between 1 and 2"); return; } Synchronized sync(m_outputDataSemaphore); m_outputData.data.quad_index_enable &= ~(1 << (encoderNumber - 1)); if (enable) m_outputData.data.quad_index_enable |= 1 << (encoderNumber - 1); m_configChanged = true; } /** * Get the value of the Capacitive Sense touch slider. * * @return Value between 0.0 (toward center of board) and 1.0 (toward edge of board). -1.0 means no touch detected. */ double DriverStationEnhancedIO::GetTouchSlider() { if (!m_inputValid) { wpi_setWPIError(EnhancedIOMissing); return 0.0; } HALReport(HALUsageReporting::kResourceType_DriverStationEIO, 1, HALUsageReporting::kDriverStationEIO_TouchSlider); Synchronized sync(m_inputDataSemaphore); uint8_t value = m_inputData.data.capsense_slider; return value == 255 ? -1.0 : value / 254.0; } /** * Get the percent duty-cycle that the PWM generator channel is configured to output. * * @param channel The DIO line's PWM generator to get the duty-cycle from. [1,4] * @return The percent duty-cycle being output (if the DIO line is configured for PWM). [0.0,1.0] */ double DriverStationEnhancedIO::GetPWMOutput(uint32_t channel) { if (channel < 1 || channel > 4) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 4"); return 0.0; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return 0.0; } Synchronized sync(m_outputDataSemaphore); return (double)m_outputData.data.pwm_compare[channel - 1] / (double)m_outputData.data.pwm_period[(channel - 1) >> 1]; } /** * Set the percent duty-cycle to output on a PWM enabled DIO line. * * DIO1 through DIO4 have the ability to output a PWM signal. The period of the * signal can be configured in pairs using SetPWMPeriod(). * * @param channel The DIO line's PWM generator to set. [1,4] * @param value The percent duty-cycle to output from the PWM generator. [0.0,1.0] */ void DriverStationEnhancedIO::SetPWMOutput(uint32_t channel, double value) { if (channel < 1 || channel > 4) { wpi_setWPIErrorWithContext(ParameterOutOfRange, "channel must be between 1 and 4"); return; } if (!m_outputValid) { wpi_setWPIError(EnhancedIOMissing); return; } static uint8_t reported_mask = 0; if (!(reported_mask & (1 >> channel))) { HALReport(HALUsageReporting::kResourceType_DriverStationEIO, channel, HALUsageReporting::kDriverStationEIO_PWM); reported_mask |= (1 >> channel); } if (value > 1.0) value = 1.0; else if (value < 0.0) value = 0.0; Synchronized sync(m_outputDataSemaphore); m_outputData.data.pwm_compare[channel - 1] = (uint16_t)(value * (double)m_outputData.data.pwm_period[(channel - 1) >> 1]); } /** * Get the firmware version running on the IO board. * * This also has the side effect of forcing the driver station to switch to Enhanced mode if it is not. * If you plan to switch between Driver Stations with unknown IO configurations, you can call this * until it returns a non-0 version to ensure that this API is accessible before proceeding. * * @return The version of the firmware running on the IO board. 0 if the board is not attached or not in Enhanced mode. */ uint8_t DriverStationEnhancedIO::GetFirmwareVersion() { if (!m_inputValid) { m_requestEnhancedEnable = true; wpi_setWPIError(EnhancedIOMissing); return 0; } Synchronized sync(m_inputDataSemaphore); return m_inputData.data.fw_version; }