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.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 the analog signal is inside the range defined by the 026 * 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 vice 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 public static class AnalogTriggerOutputException extends RuntimeException { 044 /** 045 * Create a new exception with the given message. 046 * 047 * @param message the message to pass with the exception 048 */ 049 public AnalogTriggerOutputException(String message) { 050 super(message); 051 } 052 } 053 054 private final AnalogTrigger m_trigger; 055 private final AnalogTriggerType m_outputType; 056 057 /** 058 * Create an object that represents one of the four outputs from an analog trigger. 059 * 060 * <p>Because this class derives from DigitalSource, it can be passed into routing functions for 061 * Counter, Encoder, etc. 062 * 063 * @param trigger The trigger for which this is an output. 064 * @param outputType An enum that specifies the output on the trigger to represent. 065 */ 066 public AnalogTriggerOutput(AnalogTrigger trigger, final AnalogTriggerType outputType) { 067 requireNonNullParam(trigger, "trigger", "AnalogTriggerOutput"); 068 requireNonNullParam(outputType, "outputType", "AnalogTriggerOutput"); 069 070 m_trigger = trigger; 071 m_outputType = outputType; 072 HAL.report( 073 tResourceType.kResourceType_AnalogTriggerOutput, 074 trigger.getIndex() + 1, 075 outputType.value + 1); 076 } 077 078 /** 079 * Get the state of the analog trigger output. 080 * 081 * @return The state of the analog trigger output. 082 */ 083 public boolean get() { 084 return AnalogJNI.getAnalogTriggerOutput(m_trigger.m_port, m_outputType.value); 085 } 086 087 @Override 088 public int getPortHandleForRouting() { 089 return m_trigger.m_port; 090 } 091 092 @Override 093 public int getAnalogTriggerTypeForRouting() { 094 return m_outputType.value; 095 } 096 097 @Override 098 public int getChannel() { 099 return m_trigger.getIndex(); 100 } 101 102 @Override 103 public boolean isAnalogTrigger() { 104 return true; 105 } 106 107 /** Defines the state in which the AnalogTrigger triggers. */ 108 public enum AnalogTriggerType { 109 /** In window. */ 110 kInWindow(AnalogJNI.AnalogTriggerType.kInWindow), 111 /** State. */ 112 kState(AnalogJNI.AnalogTriggerType.kState), 113 /** Rising pulse. */ 114 kRisingPulse(AnalogJNI.AnalogTriggerType.kRisingPulse), 115 /** Falling pulse. */ 116 kFallingPulse(AnalogJNI.AnalogTriggerType.kFallingPulse); 117 118 private final int value; 119 120 AnalogTriggerType(int value) { 121 this.value = value; 122 } 123 } 124 125 @Override 126 public void initSendable(SendableBuilder builder) {} 127}