mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +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;
|
||||
}
|
||||
Reference in New Issue
Block a user