mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-27 02:01:42 +00:00
artf4700: Added DigitalGlitchFilter
Initial Java support from Tyler Veness. Final java support done by Jerry Morrison. Change-Id: I1f85eb555f9ea4c0250c4c6729d7c51a76f5bef4
This commit is contained in:
committed by
Peter Johnson
parent
6d00b77ef3
commit
b3b03c43c8
@@ -46,6 +46,13 @@ extern "C"
|
||||
bool isPulsing(void* digital_port_pointer, int32_t *status);
|
||||
bool isAnyPulsing(int32_t *status);
|
||||
|
||||
void setFilterSelect(void* digital_port_pointer, int filter_index,
|
||||
int32_t* status);
|
||||
int getFilterSelect(void* digital_port_pointer, int32_t* status);
|
||||
|
||||
void setFilterPeriod(int filter_index, uint32_t value, int32_t* status);
|
||||
uint32_t getFilterPeriod(int filter_index, int32_t* status);
|
||||
|
||||
void* initializeCounter(Mode mode, uint32_t *index, int32_t *status);
|
||||
void freeCounter(void* counter_pointer, int32_t *status);
|
||||
void setCounterAverageSize(void* counter_pointer, int32_t size, int32_t *status);
|
||||
|
||||
@@ -95,6 +95,7 @@ namespace HALUsageReporting
|
||||
kResourceType_VictorSP,
|
||||
kResourceType_TalonSRX,
|
||||
kResourceType_CANTalonSRX,
|
||||
kResourceType_DigitalGlitchFilter,
|
||||
};
|
||||
|
||||
enum tInstances
|
||||
|
||||
@@ -649,6 +649,97 @@ bool isAnyPulsing(int32_t *status) {
|
||||
return pulseRegister.Headers != 0 && pulseRegister.MXP != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the filter index from the FPGA.
|
||||
* Set the filter index used to filter out short pulses.
|
||||
*
|
||||
* @param digital_port_pointer The digital I/O channel
|
||||
* @param filter_index The filter index. Must be in the range 0 - 3,
|
||||
* where 0 means "none" and 1 - 3 means filter # filter_index - 1.
|
||||
*/
|
||||
void setFilterSelect(void* digital_port_pointer, int filter_index,
|
||||
int32_t* status) {
|
||||
DigitalPort* port = (DigitalPort*)digital_port_pointer;
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
if (port->port.pin < kNumHeaders) {
|
||||
digitalSystem->writeFilterSelectHdr(port->port.pin, filter_index, status);
|
||||
}
|
||||
else {
|
||||
digitalSystem->writeFilterSelectMXP(remapMXPChannel(port->port.pin),
|
||||
filter_index, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read the filter index from the FPGA.
|
||||
* Get the filter index used to filter out short pulses.
|
||||
*
|
||||
* @param digital_port_pointer The digital I/O channel
|
||||
* @return filter_index The filter index. Must be in the range 0 - 3,
|
||||
* where 0 means "none" and 1 - 3 means filter # filter_index - 1.
|
||||
*/
|
||||
int getFilterSelect(void* digital_port_pointer, int32_t* status) {
|
||||
DigitalPort* port = (DigitalPort*)digital_port_pointer;
|
||||
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
if (port->port.pin < kNumHeaders) {
|
||||
return digitalSystem->readFilterSelectHdr(port->port.pin, status);
|
||||
}
|
||||
else {
|
||||
return digitalSystem->readFilterSelectMXP(remapMXPChannel(port->port.pin),
|
||||
status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the filter period for the specified filter index.
|
||||
*
|
||||
* Set the filter period in FPGA cycles. Even though there are 2 different
|
||||
* filter index domains (MXP vs HDR), ignore that distinction for now since it
|
||||
* compilicates the interface. That can be changed later.
|
||||
*
|
||||
* @param filter_index The filter index, 0 - 2.
|
||||
* @param value The number of cycles that the signal must not transition to be
|
||||
* counted as a transition.
|
||||
*/
|
||||
void setFilterPeriod(int filter_index, uint32_t value, int32_t* status) {
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
digitalSystem->writeFilterPeriodHdr(filter_index, value, status);
|
||||
if (*status == 0) {
|
||||
digitalSystem->writeFilterPeriodMXP(filter_index, value, status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the filter period for the specified filter index.
|
||||
*
|
||||
* Get the filter period in FPGA cycles. Even though there are 2 different
|
||||
* filter index domains (MXP vs HDR), ignore that distinction for now since it
|
||||
* compilicates the interface. Set status to NiFpga_Status_SoftwareFault if the
|
||||
* filter values miss-match.
|
||||
*
|
||||
* @param filter_index The filter index, 0 - 2.
|
||||
* @param value The number of cycles that the signal must not transition to be
|
||||
* counted as a transition.
|
||||
*/
|
||||
uint32_t getFilterPeriod(int filter_index, int32_t* status) {
|
||||
uint32_t hdr_period = 0;
|
||||
uint32_t mxp_period = 0;
|
||||
{
|
||||
std::lock_guard<priority_recursive_mutex> sync(digitalDIOMutex);
|
||||
hdr_period = digitalSystem->readFilterPeriodHdr(filter_index, status);
|
||||
if (*status == 0) {
|
||||
mxp_period = digitalSystem->readFilterPeriodMXP(filter_index, status);
|
||||
}
|
||||
}
|
||||
if (hdr_period != mxp_period) {
|
||||
*status = NiFpga_Status_SoftwareFault;
|
||||
return -1;
|
||||
}
|
||||
return hdr_period;
|
||||
}
|
||||
|
||||
struct counter_t {
|
||||
tCounter* counter;
|
||||
uint32_t index;
|
||||
|
||||
@@ -73,6 +73,7 @@ namespace nUsageReporting
|
||||
kResourceType_VictorSP,
|
||||
kResourceType_TalonSRX,
|
||||
kResourceType_CANTalonSRX,
|
||||
kResourceType_DigitalGlitchFilter,
|
||||
} tResourceType;
|
||||
|
||||
typedef enum
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
class DigitalGlitchFilter;
|
||||
|
||||
/**
|
||||
* Class for counting the number of ticks on a digital input channel.
|
||||
* This is a general purpose class for counting repetitive events. It can return
|
||||
@@ -119,4 +121,5 @@ class Counter : public SensorBase,
|
||||
uint32_t m_index = 0; ///< The index of this counter.
|
||||
|
||||
std::shared_ptr<ITable> m_table;
|
||||
friend class DigitalGlitchFilter;
|
||||
};
|
||||
|
||||
50
wpilibc/Athena/include/DigitalGlitchFilter.h
Normal file
50
wpilibc/Athena/include/DigitalGlitchFilter.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "HAL/cpp/priority_mutex.h"
|
||||
#include "DigitalSource.h"
|
||||
|
||||
class Encoder;
|
||||
class Counter;
|
||||
|
||||
/**
|
||||
* Class to enable glitch filtering on a set of digital inputs.
|
||||
* This class will manage adding and removing digital inputs from a FPGA glitch
|
||||
* filter. The filter lets the user configure the time that an input must remain
|
||||
* high or low before it is classified as high or low.
|
||||
*/
|
||||
class DigitalGlitchFilter : public SensorBase {
|
||||
public:
|
||||
DigitalGlitchFilter();
|
||||
~DigitalGlitchFilter();
|
||||
|
||||
void Add(DigitalSource *input);
|
||||
void Add(Encoder *input);
|
||||
void Add(Counter *input);
|
||||
|
||||
void Remove(DigitalSource *input);
|
||||
void Remove(Encoder *input);
|
||||
void Remove(Counter *input);
|
||||
|
||||
void SetPeriodCycles(uint32_t fpga_cycles);
|
||||
void SetPeriodNanoSeconds(uint64_t nanoseconds);
|
||||
|
||||
uint32_t GetPeriodCycles();
|
||||
uint64_t GetPeriodNanoSeconds();
|
||||
|
||||
private:
|
||||
// Sets the filter for the input to be the requested index. A value of 0
|
||||
// disables the filter, and the filter value must be between 1 and 3,
|
||||
// inclusive.
|
||||
void DoAdd(DigitalSource *input, int requested_index);
|
||||
|
||||
int m_channelIndex = -1;
|
||||
static priority_mutex m_mutex;
|
||||
static ::std::array<bool, 3> m_filterAllocated;
|
||||
};
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
|
||||
class DigitalGlitchFilter;
|
||||
|
||||
/**
|
||||
* Class to read a digital input.
|
||||
* This class will read digital inputs and return the current value on the
|
||||
@@ -45,4 +47,5 @@ class DigitalInput : public DigitalSource, public LiveWindowSendable {
|
||||
uint32_t m_channel;
|
||||
|
||||
std::shared_ptr<ITable> m_table;
|
||||
friend class DigitalGlitchFilter;
|
||||
};
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include <memory>
|
||||
|
||||
class DigitalSource;
|
||||
class DigitalGlitchFilter;
|
||||
|
||||
/**
|
||||
* Class to read quad encoders.
|
||||
@@ -116,4 +117,5 @@ class Encoder : public SensorBase,
|
||||
int32_t m_encodingScale; // 1x, 2x, or 4x, per the encodingType
|
||||
|
||||
std::shared_ptr<ITable> m_table;
|
||||
friend class DigitalGlitchFilter;
|
||||
};
|
||||
|
||||
@@ -68,6 +68,7 @@ typedef enum {
|
||||
kResourceType_VictorSP,
|
||||
kResourceType_TalonSRX,
|
||||
kResourceType_CANTalonSRX,
|
||||
kResourceType_DigitalGlitchFilter,
|
||||
} tResourceType;
|
||||
|
||||
typedef enum {
|
||||
|
||||
198
wpilibc/Athena/src/DigitalGlitchFilter.cpp
Normal file
198
wpilibc/Athena/src/DigitalGlitchFilter.cpp
Normal file
@@ -0,0 +1,198 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. 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 <algorithm>
|
||||
#include <array>
|
||||
|
||||
#include "DigitalGlitchFilter.h"
|
||||
#include "Resource.h"
|
||||
#include "WPIErrors.h"
|
||||
#include "Encoder.h"
|
||||
#include "Counter.h"
|
||||
#include "Utility.h"
|
||||
|
||||
std::array<bool, 3> DigitalGlitchFilter::m_filterAllocated = {{false, false,
|
||||
false}};
|
||||
priority_mutex DigitalGlitchFilter::m_mutex;
|
||||
|
||||
DigitalGlitchFilter::DigitalGlitchFilter() {
|
||||
std::lock_guard<priority_mutex> sync(m_mutex);
|
||||
auto index =
|
||||
std::find(m_filterAllocated.begin(), m_filterAllocated.end(), false);
|
||||
wpi_assert(index != m_filterAllocated.end());
|
||||
|
||||
m_channelIndex = std::distance(m_filterAllocated.begin(), index);
|
||||
*index = true;
|
||||
}
|
||||
|
||||
DigitalGlitchFilter::~DigitalGlitchFilter() {
|
||||
if (m_channelIndex >= 0) {
|
||||
std::lock_guard<priority_mutex> sync(m_mutex);
|
||||
m_filterAllocated[m_channelIndex] = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the DigitalSource to this glitch filter.
|
||||
*
|
||||
* @param input The DigitalSource to add.
|
||||
*/
|
||||
void DigitalGlitchFilter::Add(DigitalSource *input) {
|
||||
DoAdd(input, m_channelIndex + 1);
|
||||
}
|
||||
|
||||
void DigitalGlitchFilter::DoAdd(DigitalSource *input, int requested_index) {
|
||||
// Some sources from Counters and Encoders are null. By pushing the check
|
||||
// here, we catch the issue more generally.
|
||||
if (input) {
|
||||
int32_t status = 0;
|
||||
setFilterSelect(m_digital_ports[input->GetChannelForRouting()],
|
||||
requested_index, &status);
|
||||
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
||||
|
||||
// Validate that we set it correctly.
|
||||
int actual_index = getFilterSelect(
|
||||
m_digital_ports[input->GetChannelForRouting()], &status);
|
||||
wpi_assertEqual(actual_index, requested_index);
|
||||
|
||||
HALReport(HALUsageReporting::kResourceType_DigitalInput,
|
||||
input->GetChannelForRouting());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the Encoder to this glitch filter.
|
||||
*
|
||||
* @param input The Encoder to add.
|
||||
*/
|
||||
void DigitalGlitchFilter::Add(Encoder *input) {
|
||||
Add(input->m_aSource.get());
|
||||
if (StatusIsFatal()) {
|
||||
return;
|
||||
}
|
||||
Add(input->m_bSource.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the Counter to this glitch filter.
|
||||
*
|
||||
* @param input The Counter to add.
|
||||
*/
|
||||
void DigitalGlitchFilter::Add(Counter *input) {
|
||||
Add(input->m_upSource.get());
|
||||
if (StatusIsFatal()) {
|
||||
return;
|
||||
}
|
||||
Add(input->m_downSource.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a digital input from this filter.
|
||||
*
|
||||
* Removes the DigitalSource from this glitch filter and re-assigns it to
|
||||
* the default filter.
|
||||
*
|
||||
* @param input The DigitalSource to remove.
|
||||
*/
|
||||
void DigitalGlitchFilter::Remove(DigitalSource *input) {
|
||||
DoAdd(input, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an encoder from this filter.
|
||||
*
|
||||
* Removes the Encoder from this glitch filter and re-assigns it to
|
||||
* the default filter.
|
||||
*
|
||||
* @param input The Encoder to remove.
|
||||
*/
|
||||
void DigitalGlitchFilter::Remove(Encoder *input) {
|
||||
Remove(input->m_aSource.get());
|
||||
if (StatusIsFatal()) {
|
||||
return;
|
||||
}
|
||||
Remove(input->m_bSource.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a counter from this filter.
|
||||
*
|
||||
* Removes the Counter from this glitch filter and re-assigns it to
|
||||
* the default filter.
|
||||
*
|
||||
* @param input The Counter to remove.
|
||||
*/
|
||||
void DigitalGlitchFilter::Remove(Counter *input) {
|
||||
Remove(input->m_upSource.get());
|
||||
if (StatusIsFatal()) {
|
||||
return;
|
||||
}
|
||||
Remove(input->m_downSource.get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of cycles that the input must not change state for.
|
||||
*
|
||||
* @param fpga_cycles The number of FPGA cycles.
|
||||
*/
|
||||
void DigitalGlitchFilter::SetPeriodCycles(uint32_t fpga_cycles) {
|
||||
int32_t status = 0;
|
||||
setFilterPeriod(m_channelIndex, fpga_cycles, &status);
|
||||
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
||||
|
||||
HALReport(HALUsageReporting::kResourceType_DigitalGlitchFilter,
|
||||
m_channelIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of nanoseconds that the input must not change state for.
|
||||
*
|
||||
* @param nanoseconds The number of nanoseconds.
|
||||
*/
|
||||
void DigitalGlitchFilter::SetPeriodNanoSeconds(uint64_t nanoseconds) {
|
||||
int32_t status = 0;
|
||||
uint32_t fpga_cycles =
|
||||
nanoseconds * kSystemClockTicksPerMicrosecond / 4 / 1000;
|
||||
setFilterPeriod(m_channelIndex, fpga_cycles, &status);
|
||||
|
||||
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
||||
|
||||
HALReport(HALUsageReporting::kResourceType_DigitalGlitchFilter,
|
||||
m_channelIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of cycles that the input must not change state for.
|
||||
*
|
||||
* @return The number of cycles.
|
||||
*/
|
||||
uint32_t DigitalGlitchFilter::GetPeriodCycles() {
|
||||
int32_t status = 0;
|
||||
uint32_t fpga_cycles = getFilterPeriod(m_channelIndex, &status);
|
||||
|
||||
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
||||
|
||||
HALReport(HALUsageReporting::kResourceType_DigitalGlitchFilter,
|
||||
m_channelIndex);
|
||||
return fpga_cycles;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of nanoseconds that the input must not change state for.
|
||||
*
|
||||
* @return The number of nanoseconds.
|
||||
*/
|
||||
uint64_t DigitalGlitchFilter::GetPeriodNanoSeconds() {
|
||||
int32_t status = 0;
|
||||
uint32_t fpga_cycles = getFilterPeriod(m_channelIndex, &status);
|
||||
|
||||
wpi_setErrorWithContext(status, getHALErrorMessage(status));
|
||||
|
||||
HALReport(HALUsageReporting::kResourceType_DigitalGlitchFilter,
|
||||
m_channelIndex);
|
||||
return static_cast<uint64_t>(fpga_cycles) * 1000L /
|
||||
static_cast<uint64_t>(kSystemClockTicksPerMicrosecond / 4);
|
||||
}
|
||||
60
wpilibcIntegrationTests/src/DigitalGlitchFilterTest.cpp
Normal file
60
wpilibcIntegrationTests/src/DigitalGlitchFilterTest.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. 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 the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <Counter.h>
|
||||
#include <DigitalInput.h>
|
||||
#include <Encoder.h>
|
||||
#include <DigitalGlitchFilter.h>
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
/**
|
||||
* Tests that configuring inputs to be filtered succeeds.
|
||||
*
|
||||
* This test actually tests everything except that the actual FPGA
|
||||
* implementation works as intended. We configure the FPGA and then query it to
|
||||
* make sure that the acutal configuration matches.
|
||||
*/
|
||||
TEST(DigitalGlitchFilterTest, BasicTest) {
|
||||
DigitalInput input1(1);
|
||||
DigitalInput input2(2);
|
||||
DigitalInput input3(3);
|
||||
DigitalInput input4(4);
|
||||
Encoder encoder5(5, 6);
|
||||
Counter counter7(7);
|
||||
|
||||
// Check that we can make a single filter and set the period.
|
||||
DigitalGlitchFilter filter1;
|
||||
filter1.Add(&input1);
|
||||
filter1.SetPeriodNanoSeconds(4200);
|
||||
|
||||
// Check that we can make a second filter with 2 inputs.
|
||||
DigitalGlitchFilter filter2;
|
||||
filter2.Add(&input2);
|
||||
filter2.Add(&input3);
|
||||
filter2.SetPeriodNanoSeconds(97100);
|
||||
|
||||
// Check that we can make a third filter with an input, an encoder, and a
|
||||
// counter.
|
||||
DigitalGlitchFilter filter3;
|
||||
filter3.Add(&input4);
|
||||
filter3.Add(&encoder5);
|
||||
filter3.Add(&counter7);
|
||||
filter3.SetPeriodNanoSeconds(167800);
|
||||
|
||||
// Verify that the period was properly set for all 3 filters.
|
||||
EXPECT_EQ(4200u, filter1.GetPeriodNanoSeconds());
|
||||
EXPECT_EQ(97100u, filter2.GetPeriodNanoSeconds());
|
||||
EXPECT_EQ(167800u, filter3.GetPeriodNanoSeconds());
|
||||
|
||||
// Clean up.
|
||||
filter1.Remove(&input1);
|
||||
filter2.Remove(&input2);
|
||||
filter2.Remove(&input3);
|
||||
filter3.Remove(&input4);
|
||||
filter3.Remove(&encoder5);
|
||||
filter3.Remove(&counter7);
|
||||
}
|
||||
@@ -142,6 +142,7 @@ task jniHeaders {
|
||||
args 'edu.wpi.first.wpilibj.hal.AccelerometerJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.AnalogJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.CounterJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.DIOJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.EncoderJNI'
|
||||
args 'edu.wpi.first.wpilibj.hal.I2CJNI'
|
||||
@@ -161,4 +162,4 @@ task jniHeaders {
|
||||
|
||||
clean {
|
||||
delete generatedJNIHeaderLoc
|
||||
}
|
||||
}
|
||||
|
||||
61
wpilibj/src/athena/cpp/lib/DigitalGlitchFilterJNI.cpp
Normal file
61
wpilibj/src/athena/cpp/lib/DigitalGlitchFilterJNI.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#include <jni.h>
|
||||
#include "HAL/HAL.hpp"
|
||||
#include "HALUtil.h"
|
||||
|
||||
#include "edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI.h"
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI
|
||||
* Method: setFilterSelect
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI_setFilterSelect
|
||||
(JNIEnv* env, jclass, jlong port_pointer, jint filter_index)
|
||||
{
|
||||
int32_t status = 0;
|
||||
void* digital_port_pointer = reinterpret_cast<void*>(port_pointer);
|
||||
|
||||
setFilterSelect(digital_port_pointer, filter_index, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI
|
||||
* Method: getFilterSelect
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI_getFilterSelect
|
||||
(JNIEnv *env, jclass, jlong port_pointer)
|
||||
{
|
||||
int32_t status = 0;
|
||||
void* digital_port_pointer = reinterpret_cast<void*>(port_pointer);
|
||||
|
||||
jint result = getFilterSelect(digital_port_pointer, &status);
|
||||
CheckStatus(env, status);
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI
|
||||
* Method: setFilterPeriod
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI_setFilterPeriod
|
||||
(JNIEnv *env, jclass, jint filter_index, jint fpga_cycles)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
setFilterPeriod(filter_index, fpga_cycles, &status);
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI
|
||||
* Method: getFilterPeriod
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_edu_wpi_first_wpilibj_hal_DigitalGlitchFilterJNI_getFilterPeriod
|
||||
(JNIEnv *env, jclass, jint filter_index)
|
||||
{
|
||||
int32_t status = 0;
|
||||
|
||||
jint result = getFilterPeriod(filter_index, &status);
|
||||
CheckStatus(env, status);
|
||||
return result;
|
||||
}
|
||||
@@ -60,8 +60,8 @@ public class Counter extends SensorBase implements CounterBase, LiveWindowSendab
|
||||
}
|
||||
}
|
||||
|
||||
private DigitalSource m_upSource; // /< What makes the counter count up.
|
||||
private DigitalSource m_downSource; // /< What makes the counter count down.
|
||||
protected DigitalSource m_upSource; // /< What makes the counter count up.
|
||||
protected DigitalSource m_downSource; // /< What makes the counter count down.
|
||||
private boolean m_allocatedUpSource;
|
||||
private boolean m_allocatedDownSource;
|
||||
private long m_counter; // /< The FPGA counter object.
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2015. 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. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import edu.wpi.first.wpilibj.DigitalSource;
|
||||
import edu.wpi.first.wpilibj.Encoder;
|
||||
import edu.wpi.first.wpilibj.Counter;
|
||||
|
||||
import edu.wpi.first.wpilibj.hal.DigitalGlitchFilterJNI;
|
||||
|
||||
/**
|
||||
* Class to enable glitch filtering on a set of digital inputs.
|
||||
* This class will manage adding and removing digital inputs from a FPGA glitch
|
||||
* filter. The filter lets the user configure the time that an input must remain
|
||||
* high or low before it is classified as high or low.
|
||||
*/
|
||||
public class DigitalGlitchFilter extends SensorBase {
|
||||
public DigitalGlitchFilter() {
|
||||
synchronized(m_mutex) {
|
||||
int i = 0;
|
||||
while (m_filterAllocated[i] != false && i < m_filterAllocated.length) {
|
||||
i++;
|
||||
}
|
||||
if (i != m_filterAllocated.length) {
|
||||
m_channelIndex = i;
|
||||
m_filterAllocated[i] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void free() {
|
||||
if (m_channelIndex >= 0) {
|
||||
synchronized(m_mutex) {
|
||||
m_filterAllocated[m_channelIndex] = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void setFilter(DigitalSource input, int channelIndex) {
|
||||
if (input != null) { // Counter might have just one input
|
||||
DigitalGlitchFilterJNI.setFilterSelect(input.m_port, channelIndex);
|
||||
|
||||
int selected = DigitalGlitchFilterJNI.getFilterSelect(input.m_port);
|
||||
if (selected != channelIndex) {
|
||||
throw new IllegalStateException("DigitalGlitchFilterJNI.setFilterSelect("
|
||||
+ channelIndex + ") failed -> " + selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the DigitalSource to this glitch filter.
|
||||
*
|
||||
* @param input The DigitalSource to add.
|
||||
*/
|
||||
public void add(DigitalSource input) {
|
||||
setFilter(input, m_channelIndex + 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the Encoder to this glitch filter.
|
||||
*
|
||||
* @param input The Encoder to add.
|
||||
*/
|
||||
public void add(Encoder input) {
|
||||
add(input.m_aSource);
|
||||
add(input.m_bSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the Counter to this glitch filter.
|
||||
*
|
||||
* @param input The Counter to add.
|
||||
*/
|
||||
public void add(Counter input) {
|
||||
add(input.m_upSource);
|
||||
add(input.m_downSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this filter from the given digital input.
|
||||
*
|
||||
* @param input The DigitalSource to stop filtering.
|
||||
*/
|
||||
public void remove(DigitalSource input) {
|
||||
setFilter(input, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this filter from the given Encoder.
|
||||
*
|
||||
* @param input the Encoder to stop filtering.
|
||||
*/
|
||||
public void remove(Encoder input) {
|
||||
remove(input.m_aSource);
|
||||
remove(input.m_bSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes this filter from the given Counter.
|
||||
*
|
||||
* @param input The Counter to stop filtering.
|
||||
*/
|
||||
public void remove(Counter input) {
|
||||
remove(input.m_upSource);
|
||||
remove(input.m_downSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of FPGA cycles that the input must hold steady to pass
|
||||
* through this glitch filter.
|
||||
*
|
||||
* @param fpga_cycles The number of FPGA cycles.
|
||||
*/
|
||||
public void setPeriodCycles(int fpga_cycles) {
|
||||
DigitalGlitchFilterJNI.setFilterPeriod(m_channelIndex, fpga_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number of nanoseconds that the input must hold steady to pass
|
||||
* through this glitch filter.
|
||||
*
|
||||
* @param nanoseconds The number of nanoseconds.
|
||||
*/
|
||||
public void setPeriodNanoSeconds(long nanoseconds) {
|
||||
int fpga_cycles = (int) (nanoseconds * kSystemClockTicksPerMicrosecond / 4 /
|
||||
1000);
|
||||
setPeriodCycles(fpga_cycles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of FPGA cycles that the input must hold steady to pass
|
||||
* through this glitch filter.
|
||||
*
|
||||
* @return The number of cycles.
|
||||
*/
|
||||
public int getPeriodCycles() {
|
||||
return DigitalGlitchFilterJNI.getFilterPeriod(m_channelIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of nanoseconds that the input must hold steady to pass
|
||||
* through this glitch filter.
|
||||
*
|
||||
* @return The number of nanoseconds.
|
||||
*/
|
||||
public long getPeriodNanoSeconds() {
|
||||
int fpga_cycles = getPeriodCycles();
|
||||
|
||||
return (long) fpga_cycles * 1000L /
|
||||
(long) (kSystemClockTicksPerMicrosecond / 4);
|
||||
}
|
||||
|
||||
private int m_channelIndex = -1;
|
||||
private static final Lock m_mutex = new ReentrantLock(true);
|
||||
private static final boolean[] m_filterAllocated = new boolean[3];
|
||||
};
|
||||
@@ -379,6 +379,11 @@ public class FRCNetworkCommunicationsLibrary extends JNIWrapper {
|
||||
* src\main\include\NetworkCommunication\UsageReporting.h:62</i>
|
||||
*/
|
||||
public static final int kResourceType_CANTalonSRX = 52;
|
||||
/**
|
||||
* <i>native declaration :
|
||||
* src\main\include\NetworkCommunication\UsageReporting.h:63</i>
|
||||
*/
|
||||
public static final int kResourceType_DigitalGlitchFilter = 53;
|
||||
};
|
||||
/**
|
||||
* <i>native declaration :
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package edu.wpi.first.wpilibj.hal;
|
||||
|
||||
public class DigitalGlitchFilterJNI extends JNIWrapper {
|
||||
public static native void setFilterSelect(long digital_port_pointer, int filter_index);
|
||||
public static native int getFilterSelect(long digital_port_pointer);
|
||||
public static native void setFilterPeriod(int filter_index, int fpga_cycles);
|
||||
public static native int getFilterPeriod(int filter_index);
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) FIRST 2008-2015. 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 the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import edu.wpi.first.wpilibj.test.AbstractComsSetup;
|
||||
|
||||
import edu.wpi.first.wpilibj.DigitalInput;
|
||||
import edu.wpi.first.wpilibj.Encoder;
|
||||
import edu.wpi.first.wpilibj.Counter;
|
||||
import edu.wpi.first.wpilibj.DigitalGlitchFilter;
|
||||
|
||||
/**
|
||||
* Test for the DigitalGlitchFilter class.
|
||||
*
|
||||
* @author Austin Schuh and Jerry Morrison
|
||||
*/
|
||||
public class DigitalGlitchFilterTest extends AbstractComsSetup {
|
||||
private static final Logger logger = Logger.getLogger(
|
||||
DigitalGlitchFilterTest.class.getName());
|
||||
|
||||
protected Logger getClassLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a test to make sure that filters can be created and are consistent.
|
||||
* This assumes that the FPGA implementation to actually implement the filter
|
||||
* has been tested. It does validate that we are successfully able to set and
|
||||
* get the active filters for ports and makes sure that the FPGA filter is
|
||||
* changed correctly, and does the same for the period.
|
||||
*/
|
||||
@Test
|
||||
public void testDigitalGlitchFilterBasic() {
|
||||
DigitalInput input1 = new DigitalInput(1);
|
||||
DigitalInput input2 = new DigitalInput(2);
|
||||
DigitalInput input3 = new DigitalInput(3);
|
||||
DigitalInput input4 = new DigitalInput(4);
|
||||
Encoder encoder5 = new Encoder(5, 6);
|
||||
Counter counter7 = new Counter(7);
|
||||
|
||||
DigitalGlitchFilter filter1 = new DigitalGlitchFilter();
|
||||
filter1.add(input1);
|
||||
filter1.setPeriodNanoSeconds(4200);
|
||||
|
||||
DigitalGlitchFilter filter2 = new DigitalGlitchFilter();
|
||||
filter2.add(input2);
|
||||
filter2.add(input3);
|
||||
filter2.setPeriodNanoSeconds(97100);
|
||||
|
||||
DigitalGlitchFilter filter3 = new DigitalGlitchFilter();
|
||||
filter3.add(input4);
|
||||
filter3.add(encoder5);
|
||||
filter3.add(counter7);
|
||||
filter3.setPeriodNanoSeconds(167800);
|
||||
|
||||
assertEquals(4200, filter1.getPeriodNanoSeconds());
|
||||
assertEquals(97100, filter2.getPeriodNanoSeconds());
|
||||
assertEquals(167800, filter3.getPeriodNanoSeconds());
|
||||
|
||||
filter1.remove(input1);
|
||||
|
||||
filter2.remove(input2);
|
||||
filter2.remove(input3);
|
||||
|
||||
filter3.remove(input4);
|
||||
filter3.remove(encoder5);
|
||||
filter3.remove(counter7);
|
||||
|
||||
input1.free();
|
||||
input2.free();
|
||||
input3.free();
|
||||
input4.free();
|
||||
encoder5.free();
|
||||
counter7.free();
|
||||
filter1.free();
|
||||
filter2.free();
|
||||
filter3.free();
|
||||
}
|
||||
}
|
||||
@@ -20,8 +20,9 @@ import edu.wpi.first.wpilibj.test.AbstractTestSuite;
|
||||
@RunWith(Suite.class)
|
||||
@SuiteClasses({AnalogCrossConnectTest.class, AnalogPotentiometerTest.class,
|
||||
BuiltInAccelerometerTest.class, CANTalonTest.class, CounterTest.class,
|
||||
DIOCrossConnectTest.class, EncoderTest.class, GyroTest.class, MotorEncoderTest.class,
|
||||
MotorInvertingTest.class, PCMTest.class, PDPTest.class, PIDTest.class, PreferencesTest.class,
|
||||
DigitalGlitchFilterTest.class, DIOCrossConnectTest.class, EncoderTest.class,
|
||||
GyroTest.class, MotorEncoderTest.class, MotorInvertingTest.class,
|
||||
PCMTest.class, PDPTest.class, PIDTest.class, PreferencesTest.class,
|
||||
RelayCrossConnectTest.class, SampleTest.class, TimerTest.class})
|
||||
public class WpiLibJTestSuite extends AbstractTestSuite {
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user