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 static edu.wpi.first.wpilibj.util.ErrorMessages.requireNonNullParam; 008 009import edu.wpi.first.hal.AnalogJNI; 010import edu.wpi.first.hal.FRCNetComm.tResourceType; 011import edu.wpi.first.hal.HAL; 012import edu.wpi.first.util.sendable.Sendable; 013import edu.wpi.first.util.sendable.SendableBuilder; 014 015/** 016 * Class to represent a specific output from an analog trigger. This class is used to get the 017 * current output value and also as a DigitalSource to provide routing of an output to digital 018 * subsystems on the FPGA such as Counter, Encoder, and Interrupt. 019 * 020 * <p>The TriggerState output indicates the primary output value of the trigger. If the analog 021 * signal is less than the lower limit, the output is false. If the analog value is greater than the 022 * upper limit, then the output is true. If the analog value is in between, then the trigger output 023 * state maintains its most recent value. 024 * 025 * <p>The InWindow output indicates whether or not the analog signal is inside the range defined by 026 * the limits. 027 * 028 * <p>The RisingPulse and FallingPulse outputs detect an instantaneous transition from above the 029 * upper limit to below the lower limit, and vise versa. These pulses represent a rollover condition 030 * of a sensor and can be routed to an up / down counter or to interrupts. Because the outputs 031 * generate a pulse, they cannot be read directly. To help ensure that a rollover condition is not 032 * missed, there is an average rejection filter available that operates on the upper 8 bits of a 12 033 * bit number and selects the nearest outlier of 3 samples. This will reject a sample that is (due 034 * to averaging or sampling) errantly between the two limits. This filter will fail if more than one 035 * sample in a row is errantly in between the two limits. You may see this problem if attempting to 036 * use this feature with a mechanical rollover sensor, such as a 360 degree no-stop potentiometer 037 * without signal conditioning, because the rollover transition is not sharp / clean enough. Using 038 * the averaging engine may help with this, but rotational speeds of the sensor will then be 039 * limited. 040 */ 041public class AnalogTriggerOutput extends DigitalSource implements Sendable { 042 /** Exceptions dealing with improper operation of the Analog trigger output. */ 043 @SuppressWarnings("serial") 044 public static class AnalogTriggerOutputException extends RuntimeException { 045 /** 046 * Create a new exception with the given message. 047 * 048 * @param message the message to pass with the exception 049 */ 050 public AnalogTriggerOutputException(String message) { 051 super(message); 052 } 053 } 054 055 private final AnalogTrigger m_trigger; 056 private final AnalogTriggerType m_outputType; 057 058 /** 059 * Create an object that represents one of the four outputs from an analog trigger. 060 * 061 * <p>Because this class derives from DigitalSource, it can be passed into routing functions for 062 * Counter, Encoder, etc. 063 * 064 * @param trigger The trigger for which this is an output. 065 * @param outputType An enum that specifies the output on the trigger to represent. 066 */ 067 public AnalogTriggerOutput(AnalogTrigger trigger, final AnalogTriggerType outputType) { 068 requireNonNullParam(trigger, "trigger", "AnalogTriggerOutput"); 069 requireNonNullParam(outputType, "outputType", "AnalogTriggerOutput"); 070 071 m_trigger = trigger; 072 m_outputType = outputType; 073 HAL.report( 074 tResourceType.kResourceType_AnalogTriggerOutput, 075 trigger.getIndex() + 1, 076 outputType.value + 1); 077 } 078 079 /** 080 * Get the state of the analog trigger output. 081 * 082 * @return The state of the analog trigger output. 083 */ 084 public boolean get() { 085 return AnalogJNI.getAnalogTriggerOutput(m_trigger.m_port, m_outputType.value); 086 } 087 088 @Override 089 public int getPortHandleForRouting() { 090 return m_trigger.m_port; 091 } 092 093 @Override 094 public int getAnalogTriggerTypeForRouting() { 095 return m_outputType.value; 096 } 097 098 @Override 099 public int getChannel() { 100 return m_trigger.getIndex(); 101 } 102 103 @Override 104 public boolean isAnalogTrigger() { 105 return true; 106 } 107 108 /** Defines the state in which the AnalogTrigger triggers. */ 109 public enum AnalogTriggerType { 110 kInWindow(AnalogJNI.AnalogTriggerType.kInWindow), 111 kState(AnalogJNI.AnalogTriggerType.kState), 112 kRisingPulse(AnalogJNI.AnalogTriggerType.kRisingPulse), 113 kFallingPulse(AnalogJNI.AnalogTriggerType.kFallingPulse); 114 115 private final int value; 116 117 AnalogTriggerType(int value) { 118 this.value = value; 119 } 120 } 121 122 @Override 123 public void initSendable(SendableBuilder builder) {} 124}