mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-26 01:51:41 +00:00
[wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include <hal/AnalogTrigger.h>
|
||||
#include <hal/FRCUsageReporting.h>
|
||||
#include <wpi/NullDeleter.h>
|
||||
|
||||
|
||||
@@ -4,9 +4,11 @@
|
||||
|
||||
#include "frc/AnalogTriggerOutput.h"
|
||||
|
||||
#include <hal/AnalogTrigger.h>
|
||||
#include <hal/FRCUsageReporting.h>
|
||||
|
||||
#include "frc/AnalogTrigger.h"
|
||||
#include "frc/AnalogTriggerType.h"
|
||||
#include "frc/Errors.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
67
wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp
Normal file
67
wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/AsynchronousInterrupt.h"
|
||||
|
||||
#include <frc/DigitalSource.h>
|
||||
|
||||
using namespace frc;
|
||||
|
||||
AsynchronousInterrupt::AsynchronousInterrupt(
|
||||
DigitalSource& source, std::function<void(bool, bool)> callback)
|
||||
: m_interrupt{source}, m_callback{std::move(callback)} {}
|
||||
AsynchronousInterrupt::AsynchronousInterrupt(
|
||||
DigitalSource* source, std::function<void(bool, bool)> callback)
|
||||
: m_interrupt{source}, m_callback{std::move(callback)} {}
|
||||
AsynchronousInterrupt::AsynchronousInterrupt(
|
||||
std::shared_ptr<DigitalSource> source,
|
||||
std::function<void(bool, bool)> callback)
|
||||
: m_interrupt{source}, m_callback{std::move(callback)} {}
|
||||
|
||||
AsynchronousInterrupt::~AsynchronousInterrupt() {
|
||||
Disable();
|
||||
}
|
||||
|
||||
void AsynchronousInterrupt::ThreadMain() {
|
||||
while (m_keepRunning) {
|
||||
auto result = m_interrupt.WaitForInterrupt(10_s, false);
|
||||
if (!m_keepRunning) {
|
||||
break;
|
||||
}
|
||||
if (result == SynchronousInterrupt::WaitResult::kTimeout) {
|
||||
continue;
|
||||
}
|
||||
m_callback((result & SynchronousInterrupt::WaitResult::kRisingEdge) != 0,
|
||||
(result & SynchronousInterrupt::WaitResult::kFallingEdge) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
void AsynchronousInterrupt::Enable() {
|
||||
if (m_keepRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_keepRunning = true;
|
||||
m_thread = std::thread([this] { this->ThreadMain(); });
|
||||
}
|
||||
|
||||
void AsynchronousInterrupt::Disable() {
|
||||
m_keepRunning = false;
|
||||
m_interrupt.WakeupWaitingInterrupt();
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
void AsynchronousInterrupt::SetInterruptEdges(bool risingEdge,
|
||||
bool fallingEdge) {
|
||||
m_interrupt.SetInterruptEdges(risingEdge, fallingEdge);
|
||||
}
|
||||
|
||||
units::second_t AsynchronousInterrupt::GetRisingTimestamp() {
|
||||
return m_interrupt.GetRisingTimestamp();
|
||||
}
|
||||
units::second_t AsynchronousInterrupt::GetFallingTimestamp() {
|
||||
return m_interrupt.GetFallingTimestamp();
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/InterruptableSensorBase.h"
|
||||
|
||||
#include "frc/Errors.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
InterruptableSensorBase::~InterruptableSensorBase() {
|
||||
if (m_interrupt == HAL_kInvalidHandle) {
|
||||
return;
|
||||
}
|
||||
int32_t status = 0;
|
||||
HAL_CleanInterrupts(m_interrupt, &status);
|
||||
// Ignore status, as an invalid handle just needs to be ignored.
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts(
|
||||
HAL_InterruptHandlerFunction handler, void* param) {
|
||||
FRC_Assert(m_interrupt == HAL_kInvalidHandle);
|
||||
AllocateInterrupts(false);
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_RequestInterrupts(
|
||||
m_interrupt, GetPortHandleForRouting(),
|
||||
static_cast<HAL_AnalogTriggerType>(GetAnalogTriggerTypeForRouting()),
|
||||
&status);
|
||||
SetUpSourceEdge(true, false);
|
||||
HAL_AttachInterruptHandler(m_interrupt, handler, param, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "AttachInterruptHandler");
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts(InterruptEventHandler handler) {
|
||||
FRC_Assert(m_interrupt == HAL_kInvalidHandle);
|
||||
AllocateInterrupts(false);
|
||||
|
||||
m_interruptHandler =
|
||||
std::make_unique<InterruptEventHandler>(std::move(handler));
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_RequestInterrupts(
|
||||
m_interrupt, GetPortHandleForRouting(),
|
||||
static_cast<HAL_AnalogTriggerType>(GetAnalogTriggerTypeForRouting()),
|
||||
&status);
|
||||
SetUpSourceEdge(true, false);
|
||||
HAL_AttachInterruptHandler(
|
||||
m_interrupt,
|
||||
[](uint32_t mask, void* param) {
|
||||
auto self = reinterpret_cast<InterruptEventHandler*>(param);
|
||||
// Rising edge result is the interrupt bit set in the byte 0xFF
|
||||
// Falling edge result is the interrupt bit set in the byte 0xFF00
|
||||
// Set any bit set to be true for that edge, and AND the 2 results
|
||||
// together to match the existing enum for all interrupts
|
||||
int32_t rising = (mask & 0xFF) ? 0x1 : 0x0;
|
||||
int32_t falling = ((mask & 0xFF00) ? 0x0100 : 0x0);
|
||||
WaitResult res = static_cast<WaitResult>(falling | rising);
|
||||
(*self)(res);
|
||||
},
|
||||
m_interruptHandler.get(), &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "AttachInterruptHandler");
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts() {
|
||||
FRC_Assert(m_interrupt == HAL_kInvalidHandle);
|
||||
AllocateInterrupts(true);
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_RequestInterrupts(
|
||||
m_interrupt, GetPortHandleForRouting(),
|
||||
static_cast<HAL_AnalogTriggerType>(GetAnalogTriggerTypeForRouting()),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "{}", "RequestInterrupts");
|
||||
SetUpSourceEdge(true, false);
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::CancelInterrupts() {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
HAL_CleanInterrupts(m_interrupt, &status);
|
||||
// Ignore status, as an invalid handle just needs to be ignored.
|
||||
m_interrupt = HAL_kInvalidHandle;
|
||||
m_interruptHandler = nullptr;
|
||||
}
|
||||
|
||||
InterruptableSensorBase::WaitResult InterruptableSensorBase::WaitForInterrupt(
|
||||
units::second_t timeout, bool ignorePrevious) {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
int result;
|
||||
|
||||
result = HAL_WaitForInterrupt(m_interrupt, timeout.to<double>(),
|
||||
ignorePrevious, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "WaitForInterrupt");
|
||||
|
||||
// Rising edge result is the interrupt bit set in the byte 0xFF
|
||||
// Falling edge result is the interrupt bit set in the byte 0xFF00
|
||||
// Set any bit set to be true for that edge, and AND the 2 results
|
||||
// together to match the existing enum for all interrupts
|
||||
int32_t rising = (result & 0xFF) ? 0x1 : 0x0;
|
||||
int32_t falling = ((result & 0xFF00) ? 0x0100 : 0x0);
|
||||
return static_cast<WaitResult>(falling | rising);
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::EnableInterrupts() {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
HAL_EnableInterrupts(m_interrupt, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "EnableInterrupts");
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::DisableInterrupts() {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
HAL_DisableInterrupts(m_interrupt, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "DisableInterrupts");
|
||||
}
|
||||
|
||||
units::second_t InterruptableSensorBase::ReadRisingTimestamp() {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
int64_t timestamp = HAL_ReadInterruptRisingTimestamp(m_interrupt, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "ReadRisingTimestamp");
|
||||
return units::microsecond_t(timestamp);
|
||||
}
|
||||
|
||||
units::second_t InterruptableSensorBase::ReadFallingTimestamp() {
|
||||
FRC_Assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
int64_t timestamp = HAL_ReadInterruptFallingTimestamp(m_interrupt, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "ReadFallingTimestamp");
|
||||
return units::microsecond_t(timestamp);
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::SetUpSourceEdge(bool risingEdge,
|
||||
bool fallingEdge) {
|
||||
if (m_interrupt == HAL_kInvalidHandle) {
|
||||
throw FRC_MakeError(
|
||||
err::NullParameter, "{}",
|
||||
"You must call RequestInterrupts before SetUpSourceEdge");
|
||||
}
|
||||
if (m_interrupt != HAL_kInvalidHandle) {
|
||||
int32_t status = 0;
|
||||
HAL_SetInterruptUpSourceEdge(m_interrupt, risingEdge, fallingEdge, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "SetUpSourceEdge");
|
||||
}
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::AllocateInterrupts(bool watcher) {
|
||||
FRC_Assert(m_interrupt == HAL_kInvalidHandle);
|
||||
// Expects the calling leaf class to allocate an interrupt index.
|
||||
int32_t status = 0;
|
||||
m_interrupt = HAL_InitializeInterrupts(watcher, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "AllocateInterrupts");
|
||||
}
|
||||
105
wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp
Normal file
105
wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp
Normal file
@@ -0,0 +1,105 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/SynchronousInterrupt.h"
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <hal/Interrupts.h>
|
||||
#include <wpi/NullDeleter.h>
|
||||
|
||||
#include "frc/DigitalSource.h"
|
||||
#include "frc/Errors.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
SynchronousInterrupt::SynchronousInterrupt(DigitalSource& source)
|
||||
: m_source{&source, wpi::NullDeleter<DigitalSource>()} {
|
||||
InitSynchronousInterrupt();
|
||||
}
|
||||
SynchronousInterrupt::SynchronousInterrupt(DigitalSource* source)
|
||||
: m_source{source, wpi::NullDeleter<DigitalSource>()} {
|
||||
if (m_source == nullptr) {
|
||||
FRC_CheckErrorStatus(frc::err::NullParameter, "{}", "Source is null");
|
||||
} else {
|
||||
InitSynchronousInterrupt();
|
||||
}
|
||||
}
|
||||
SynchronousInterrupt::SynchronousInterrupt(
|
||||
std::shared_ptr<DigitalSource> source)
|
||||
: m_source{std::move(source)} {
|
||||
if (m_source == nullptr) {
|
||||
FRC_CheckErrorStatus(frc::err::NullParameter, "{}", "Source is null");
|
||||
} else {
|
||||
InitSynchronousInterrupt();
|
||||
}
|
||||
}
|
||||
|
||||
void SynchronousInterrupt::InitSynchronousInterrupt() {
|
||||
int32_t status = 0;
|
||||
m_handle = HAL_InitializeInterrupts(&status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt failed to initialize");
|
||||
HAL_RequestInterrupts(m_handle, m_source->GetPortHandleForRouting(),
|
||||
static_cast<HAL_AnalogTriggerType>(
|
||||
m_source->GetAnalogTriggerTypeForRouting()),
|
||||
&status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt request failed");
|
||||
HAL_SetInterruptUpSourceEdge(m_handle, true, false, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt setting up source edge failed");
|
||||
}
|
||||
|
||||
SynchronousInterrupt::~SynchronousInterrupt() {
|
||||
HAL_CleanInterrupts(m_handle);
|
||||
}
|
||||
|
||||
inline SynchronousInterrupt::WaitResult operator|(
|
||||
SynchronousInterrupt::WaitResult lhs,
|
||||
SynchronousInterrupt::WaitResult rhs) {
|
||||
using T = std::underlying_type_t<SynchronousInterrupt::WaitResult>;
|
||||
return static_cast<SynchronousInterrupt::WaitResult>(static_cast<T>(lhs) |
|
||||
static_cast<T>(rhs));
|
||||
}
|
||||
|
||||
SynchronousInterrupt::WaitResult SynchronousInterrupt::WaitForInterrupt(
|
||||
units::second_t timeout, bool ignorePrevious) {
|
||||
int32_t status = 0;
|
||||
auto result = HAL_WaitForInterrupt(m_handle, timeout.to<double>(),
|
||||
ignorePrevious, &status);
|
||||
|
||||
auto rising =
|
||||
((result & 0xFF) != 0) ? WaitResult::kRisingEdge : WaitResult::kTimeout;
|
||||
auto falling = ((result & 0xFF00) != 0) ? WaitResult::kFallingEdge
|
||||
: WaitResult::kTimeout;
|
||||
|
||||
return rising | falling;
|
||||
}
|
||||
|
||||
void SynchronousInterrupt::SetInterruptEdges(bool risingEdge,
|
||||
bool fallingEdge) {
|
||||
int32_t status = 0;
|
||||
HAL_SetInterruptUpSourceEdge(m_handle, risingEdge, fallingEdge, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt setting edges failed");
|
||||
}
|
||||
|
||||
void SynchronousInterrupt::WakeupWaitingInterrupt() {
|
||||
int32_t status = 0;
|
||||
HAL_ReleaseWaitingInterrupt(m_handle, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt wakeup failed");
|
||||
}
|
||||
|
||||
units::second_t SynchronousInterrupt::GetRisingTimestamp() {
|
||||
int32_t status = 0;
|
||||
auto ts = HAL_ReadInterruptRisingTimestamp(m_handle, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt rising timestamp failed");
|
||||
units::microsecond_t ms{static_cast<double>(ts)};
|
||||
return ms;
|
||||
}
|
||||
|
||||
units::second_t SynchronousInterrupt::GetFallingTimestamp() {
|
||||
int32_t status = 0;
|
||||
auto ts = HAL_ReadInterruptFallingTimestamp(m_handle, &status);
|
||||
FRC_CheckErrorStatus(status, "{}", "Interrupt falling timestamp failed");
|
||||
units::microsecond_t ms{static_cast<double>(ts)};
|
||||
return ms;
|
||||
}
|
||||
150
wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h
Normal file
150
wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h
Normal file
@@ -0,0 +1,150 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <frc/SynchronousInterrupt.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
namespace frc {
|
||||
/**
|
||||
* Class for handling asynchronous interrupts.
|
||||
*
|
||||
* <p> By default, interrupts will occur on rising edge. Callbacks are disabled
|
||||
* by default, and Enable() must be called before they will occur.
|
||||
*
|
||||
* <p> Both rising and falling edge can be indiciated if both a rising and
|
||||
* falling happen between callbacks.
|
||||
*
|
||||
* <p>Synchronous interrupts are handled by the SynchronousInterrupt class.
|
||||
*/
|
||||
class AsynchronousInterrupt {
|
||||
public:
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
AsynchronousInterrupt(DigitalSource& source,
|
||||
std::function<void(bool, bool)> callback);
|
||||
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
AsynchronousInterrupt(DigitalSource* source,
|
||||
std::function<void(bool, bool)> callback);
|
||||
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
AsynchronousInterrupt(std::shared_ptr<DigitalSource> source,
|
||||
std::function<void(bool, bool)> callback);
|
||||
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
template <typename Callable, typename Arg, typename... Args>
|
||||
AsynchronousInterrupt(DigitalSource& source, Callable&& f, Arg&& arg,
|
||||
Args&&... args)
|
||||
: AsynchronousInterrupt(
|
||||
source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
|
||||
std::forward<Args>(args)...)) {}
|
||||
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
template <typename Callable, typename Arg, typename... Args>
|
||||
AsynchronousInterrupt(DigitalSource* source, Callable&& f, Arg&& arg,
|
||||
Args&&... args)
|
||||
: AsynchronousInterrupt(
|
||||
source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
|
||||
std::forward<Args>(args)...)) {}
|
||||
|
||||
/**
|
||||
* Construct an Asynchronous Interrupt from a Digital Source.
|
||||
*
|
||||
* <p> At construction, the interrupt will trigger on the rising edge.
|
||||
*
|
||||
* <p> The first bool in the callback is rising, the 2nd is falling.
|
||||
*/
|
||||
template <typename Callable, typename Arg, typename... Args>
|
||||
AsynchronousInterrupt(std::shared_ptr<DigitalSource> source, Callable&& f,
|
||||
Arg&& arg, Args&&... args)
|
||||
: AsynchronousInterrupt(
|
||||
source, std::bind(std::forward<Callable>(f), std::forward<Arg>(arg),
|
||||
std::forward<Args>(args)...)) {}
|
||||
|
||||
~AsynchronousInterrupt();
|
||||
|
||||
/**
|
||||
* Enables interrupt callbacks. Before this, callbacks will not occur. Does
|
||||
* nothing if already enabled.
|
||||
*/
|
||||
void Enable();
|
||||
|
||||
/**
|
||||
* Disables interrupt callbacks. Does nothing if already disabled.
|
||||
*/
|
||||
void Disable();
|
||||
|
||||
/**
|
||||
* Set which edges to trigger the interrupt on.
|
||||
*
|
||||
* @param risingEdge Trigger on rising edge
|
||||
* @param fallingEdge Trigger on falling edge
|
||||
*/
|
||||
void SetInterruptEdges(bool risingEdge, bool fallingEdge);
|
||||
|
||||
/**
|
||||
* Get the timestamp of the last rising edge.
|
||||
*
|
||||
* <p>This function does not require the interrupt to be enabled to work.
|
||||
*
|
||||
* <p>This only works if rising edge was configured using SetInterruptEdges.
|
||||
* @return the timestamp in seconds relative to getFPGATime
|
||||
*/
|
||||
units::second_t GetRisingTimestamp();
|
||||
|
||||
/**
|
||||
* Get the timestamp of the last falling edge.
|
||||
*
|
||||
* <p>This function does not require the interrupt to be enabled to work.
|
||||
*
|
||||
* <p>This only works if falling edge was configured using SetInterruptEdges.
|
||||
* @return the timestamp in seconds relative to getFPGATime
|
||||
*/
|
||||
units::second_t GetFallingTimestamp();
|
||||
|
||||
private:
|
||||
void ThreadMain();
|
||||
|
||||
std::atomic_bool m_keepRunning{false};
|
||||
std::thread m_thread;
|
||||
SynchronousInterrupt m_interrupt;
|
||||
std::function<void(bool, bool)> m_callback;
|
||||
};
|
||||
} // namespace frc
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
#include <hal/Types.h>
|
||||
|
||||
#include "frc/InterruptableSensorBase.h"
|
||||
#include "frc/AnalogTriggerType.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace frc {
|
||||
* constructed and freed when finished for the source. The source can either be
|
||||
* a digital input or analog trigger but not both.
|
||||
*/
|
||||
class DigitalSource : public InterruptableSensorBase {
|
||||
class DigitalSource {
|
||||
public:
|
||||
DigitalSource() = default;
|
||||
DigitalSource(DigitalSource&&) = default;
|
||||
DigitalSource& operator=(DigitalSource&&) = default;
|
||||
|
||||
HAL_Handle GetPortHandleForRouting() const override = 0;
|
||||
AnalogTriggerType GetAnalogTriggerTypeForRouting() const override = 0;
|
||||
virtual HAL_Handle GetPortHandleForRouting() const = 0;
|
||||
virtual AnalogTriggerType GetAnalogTriggerTypeForRouting() const = 0;
|
||||
virtual bool IsAnalogTrigger() const = 0;
|
||||
virtual int GetChannel() const = 0;
|
||||
};
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include <hal/Interrupts.h>
|
||||
#include <units/time.h>
|
||||
|
||||
#include "frc/AnalogTriggerType.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
class InterruptableSensorBase {
|
||||
public:
|
||||
enum WaitResult {
|
||||
kTimeout = 0x0,
|
||||
kRisingEdge = 0x1,
|
||||
kFallingEdge = 0x100,
|
||||
kBoth = 0x101,
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for interrupts.
|
||||
*
|
||||
* First parameter is if rising, 2nd is if falling.
|
||||
*/
|
||||
using InterruptEventHandler = std::function<void(WaitResult)>;
|
||||
|
||||
InterruptableSensorBase() = default;
|
||||
|
||||
/**
|
||||
* Free the resources for an interrupt event.
|
||||
*/
|
||||
virtual ~InterruptableSensorBase();
|
||||
|
||||
InterruptableSensorBase(InterruptableSensorBase&&) = default;
|
||||
InterruptableSensorBase& operator=(InterruptableSensorBase&&) = default;
|
||||
|
||||
virtual HAL_Handle GetPortHandleForRouting() const = 0;
|
||||
virtual AnalogTriggerType GetAnalogTriggerTypeForRouting() const = 0;
|
||||
|
||||
/**
|
||||
* Request one of the 8 interrupts asynchronously on this digital input.
|
||||
*
|
||||
* Request interrupts in asynchronous mode where the user's interrupt handler
|
||||
* will be called when the interrupt fires. Users that want control over the
|
||||
* thread priority should use the synchronous method with their own spawned
|
||||
* thread. The default is interrupt on rising edges only.
|
||||
*/
|
||||
virtual void RequestInterrupts(HAL_InterruptHandlerFunction handler,
|
||||
void* param);
|
||||
|
||||
/**
|
||||
* Request one of the 8 interrupts asynchronously on this digital input.
|
||||
*
|
||||
* Request interrupts in asynchronous mode where the user's interrupt handler
|
||||
* will be called when the interrupt fires. Users that want control over the
|
||||
* thread priority should use the synchronous method with their own spawned
|
||||
* thread. The default is interrupt on rising edges only.
|
||||
*/
|
||||
virtual void RequestInterrupts(InterruptEventHandler handler);
|
||||
|
||||
/**
|
||||
* Request one of the 8 interrupts synchronously on this digital input.
|
||||
*
|
||||
* Request interrupts in synchronous mode where the user program will have to
|
||||
* explicitly wait for the interrupt to occur using WaitForInterrupt.
|
||||
* The default is interrupt on rising edges only.
|
||||
*/
|
||||
virtual void RequestInterrupts();
|
||||
|
||||
/**
|
||||
* Cancel interrupts on this device.
|
||||
*
|
||||
* This deallocates all the chipobject structures and disables any interrupts.
|
||||
*/
|
||||
virtual void CancelInterrupts();
|
||||
|
||||
/**
|
||||
* In synchronous mode, wait for the defined interrupt to occur.
|
||||
*
|
||||
* You should <b>NOT</b> attempt to read the sensor from another thread while
|
||||
* waiting for an interrupt. This is not threadsafe, and can cause memory
|
||||
* corruption
|
||||
*
|
||||
* @param timeout Timeout
|
||||
* @param ignorePrevious If true, ignore interrupts that happened before
|
||||
* WaitForInterrupt was called.
|
||||
* @return What interrupts fired
|
||||
*/
|
||||
virtual WaitResult WaitForInterrupt(units::second_t timeout,
|
||||
bool ignorePrevious = true);
|
||||
|
||||
/**
|
||||
* Enable interrupts to occur on this input.
|
||||
*
|
||||
* Interrupts are disabled when the RequestInterrupt call is made. This gives
|
||||
* time to do the setup of the other options before starting to field
|
||||
* interrupts.
|
||||
*/
|
||||
virtual void EnableInterrupts();
|
||||
|
||||
/**
|
||||
* Disable Interrupts without without deallocating structures.
|
||||
*/
|
||||
virtual void DisableInterrupts();
|
||||
|
||||
/**
|
||||
* Return the timestamp for the rising interrupt that occurred most recently.
|
||||
*
|
||||
* This is in the same time domain as GetClock(). The rising-edge interrupt
|
||||
* should be enabled with SetUpSourceEdge().
|
||||
*
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
virtual units::second_t ReadRisingTimestamp();
|
||||
|
||||
/**
|
||||
* Return the timestamp for the falling interrupt that occurred most recently.
|
||||
*
|
||||
* This is in the same time domain as GetClock().
|
||||
* The falling-edge interrupt should be enabled with
|
||||
* {@link #DigitalInput.SetUpSourceEdge}
|
||||
*
|
||||
* @return Timestamp in seconds since boot.
|
||||
*/
|
||||
virtual units::second_t ReadFallingTimestamp();
|
||||
|
||||
/**
|
||||
* Set which edge to trigger interrupts on
|
||||
*
|
||||
* @param risingEdge true to interrupt on rising edge
|
||||
* @param fallingEdge true to interrupt on falling edge
|
||||
*/
|
||||
virtual void SetUpSourceEdge(bool risingEdge, bool fallingEdge);
|
||||
|
||||
protected:
|
||||
hal::Handle<HAL_InterruptHandle> m_interrupt;
|
||||
std::unique_ptr<InterruptEventHandler> m_interruptHandler{nullptr};
|
||||
|
||||
void AllocateInterrupts(bool watcher);
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
98
wpilibc/src/main/native/include/frc/SynchronousInterrupt.h
Normal file
98
wpilibc/src/main/native/include/frc/SynchronousInterrupt.h
Normal file
@@ -0,0 +1,98 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <hal/Types.h>
|
||||
#include <units/time.h>
|
||||
|
||||
namespace frc {
|
||||
class DigitalSource;
|
||||
|
||||
/**
|
||||
* Class for handling ssynchronous interrupts.
|
||||
*
|
||||
* <p> By default, interrupts will occur on rising edge.
|
||||
*
|
||||
* <p> Asynchronous interrupts are handled by the AsynchronousInterrupt class.
|
||||
*/
|
||||
class SynchronousInterrupt {
|
||||
public:
|
||||
enum WaitResult {
|
||||
kTimeout = 0x0,
|
||||
kRisingEdge = 0x1,
|
||||
kFallingEdge = 0x100,
|
||||
kBoth = 0x101,
|
||||
};
|
||||
|
||||
/**
|
||||
* Construct a Synchronous Interrupt from a Digital Source.
|
||||
*/
|
||||
explicit SynchronousInterrupt(DigitalSource& source);
|
||||
|
||||
/**
|
||||
* Construct a Synchronous Interrupt from a Digital Source.
|
||||
*/
|
||||
explicit SynchronousInterrupt(DigitalSource* source);
|
||||
|
||||
/**
|
||||
* Construct a Synchronous Interrupt from a Digital Source.
|
||||
*/
|
||||
explicit SynchronousInterrupt(std::shared_ptr<DigitalSource> source);
|
||||
|
||||
~SynchronousInterrupt();
|
||||
|
||||
SynchronousInterrupt(SynchronousInterrupt&&) = default;
|
||||
SynchronousInterrupt& operator=(SynchronousInterrupt&&) = default;
|
||||
|
||||
/**
|
||||
* Wait for an interrupt to occur.
|
||||
*
|
||||
* <p> Both rising and falling edge can be returned if both a rising and
|
||||
* falling happened between calls, and ignorePrevious is false.
|
||||
*
|
||||
* @param timeout The timeout to wait for. 0s or less will return immediately.
|
||||
* @param ignorePrevious True to ignore any previous interrupts, false to
|
||||
* return interrupt value if an interrupt has occured since last call.
|
||||
* @return The edge(s) that were triggered, or timeout.
|
||||
*/
|
||||
WaitResult WaitForInterrupt(units::second_t timeout,
|
||||
bool ignorePrevious = true);
|
||||
|
||||
/**
|
||||
* Set which edges cause an interrupt to occur.
|
||||
*
|
||||
* @param risingEdge true to trigger on rising edge, false otherwise.
|
||||
* @param fallingEdge true to trigger on falling edge, false otherwise
|
||||
*/
|
||||
void SetInterruptEdges(bool risingEdge, bool fallingEdge);
|
||||
|
||||
/**
|
||||
* Get the timestamp (relative to FPGA Time) of the last rising edge.
|
||||
*/
|
||||
units::second_t GetRisingTimestamp();
|
||||
|
||||
/**
|
||||
* Get the timestamp of the last falling edge.
|
||||
*
|
||||
* <p>This function does not require the interrupt to be enabled to work.
|
||||
*
|
||||
* <p>This only works if falling edge was configured using setInterruptEdges.
|
||||
* @return the timestamp in seconds relative to getFPGATime
|
||||
*/
|
||||
units::second_t GetFallingTimestamp();
|
||||
|
||||
/**
|
||||
* Wake up an existing wait call. Can be called from any thread.
|
||||
*/
|
||||
void WakeupWaitingInterrupt();
|
||||
|
||||
private:
|
||||
void InitSynchronousInterrupt();
|
||||
std::shared_ptr<DigitalSource> m_source;
|
||||
hal::Handle<HAL_InterruptHandle> m_handle;
|
||||
};
|
||||
} // namespace frc
|
||||
Reference in New Issue
Block a user