[wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)

This commit is contained in:
Thad House
2021-06-05 11:25:21 -07:00
committed by GitHub
parent 15c521a7fe
commit 5c817082a0
28 changed files with 982 additions and 1497 deletions

View File

@@ -6,6 +6,7 @@
#include <utility>
#include <hal/AnalogTrigger.h>
#include <hal/FRCUsageReporting.h>
#include <wpi/NullDeleter.h>

View File

@@ -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;

View 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();
}

View File

@@ -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");
}

View 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;
}