mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-05 03:21:42 +00:00
Add lambda overloads for interrupts (#1636)
This commit is contained in:
committed by
Peter Johnson
parent
90957aeea4
commit
7de9477347
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2008-2019 FIRST. 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. */
|
||||
@@ -14,6 +14,32 @@
|
||||
|
||||
using namespace frc;
|
||||
|
||||
InterruptableSensorBase::~InterruptableSensorBase() {
|
||||
if (m_interrupt == HAL_kInvalidHandle) return;
|
||||
int32_t status = 0;
|
||||
auto param = HAL_CleanInterrupts(m_interrupt, &status);
|
||||
if (param) {
|
||||
delete reinterpret_cast<InterruptEventHandler*>(param);
|
||||
}
|
||||
// Ignore status, as an invalid handle just needs to be ignored.
|
||||
m_interrupt = HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
InterruptableSensorBase::InterruptableSensorBase(InterruptableSensorBase&& rhs)
|
||||
: ErrorBase(std::move(rhs)),
|
||||
m_interrupt(rhs.m_interrupt.exchange(HAL_kInvalidHandle)) {
|
||||
rhs.m_interrupt = HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
InterruptableSensorBase& InterruptableSensorBase::operator=(
|
||||
InterruptableSensorBase&& rhs) {
|
||||
ErrorBase::operator=(std::move(rhs));
|
||||
|
||||
m_interrupt = rhs.m_interrupt.exchange(HAL_kInvalidHandle);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts(
|
||||
HAL_InterruptHandlerFunction handler, void* param) {
|
||||
if (StatusIsFatal()) return;
|
||||
@@ -32,6 +58,38 @@ void InterruptableSensorBase::RequestInterrupts(
|
||||
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts(InterruptEventHandler handler) {
|
||||
if (StatusIsFatal()) return;
|
||||
|
||||
wpi_assert(m_interrupt == HAL_kInvalidHandle);
|
||||
AllocateInterrupts(false);
|
||||
if (StatusIsFatal()) return; // if allocate failed, out of interrupts
|
||||
|
||||
auto handlerPtr = new 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);
|
||||
},
|
||||
handlerPtr, &status);
|
||||
wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
|
||||
}
|
||||
|
||||
void InterruptableSensorBase::RequestInterrupts() {
|
||||
if (StatusIsFatal()) return;
|
||||
|
||||
@@ -52,7 +110,10 @@ void InterruptableSensorBase::CancelInterrupts() {
|
||||
if (StatusIsFatal()) return;
|
||||
wpi_assert(m_interrupt != HAL_kInvalidHandle);
|
||||
int32_t status = 0;
|
||||
HAL_CleanInterrupts(m_interrupt, &status);
|
||||
auto param = HAL_CleanInterrupts(m_interrupt, &status);
|
||||
if (param) {
|
||||
delete reinterpret_cast<InterruptEventHandler*>(param);
|
||||
}
|
||||
// Ignore status, as an invalid handle just needs to be ignored.
|
||||
m_interrupt = HAL_kInvalidHandle;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2008-2019 FIRST. 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. */
|
||||
@@ -7,6 +7,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
#include <hal/Interrupts.h>
|
||||
|
||||
#include "frc/AnalogTriggerType.h"
|
||||
@@ -24,10 +27,22 @@ class InterruptableSensorBase : public ErrorBase, public SendableBase {
|
||||
kBoth = 0x101,
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for interrupts.
|
||||
*
|
||||
* First parameter is if rising, 2nd is if falling.
|
||||
*/
|
||||
using InterruptEventHandler = std::function<void(WaitResult)>;
|
||||
|
||||
InterruptableSensorBase() = default;
|
||||
|
||||
InterruptableSensorBase(InterruptableSensorBase&&) = default;
|
||||
InterruptableSensorBase& operator=(InterruptableSensorBase&&) = default;
|
||||
/**
|
||||
* Free the resources for an interrupt event.
|
||||
*/
|
||||
virtual ~InterruptableSensorBase();
|
||||
|
||||
InterruptableSensorBase(InterruptableSensorBase&&);
|
||||
InterruptableSensorBase& operator=(InterruptableSensorBase&&);
|
||||
|
||||
virtual HAL_Handle GetPortHandleForRouting() const = 0;
|
||||
virtual AnalogTriggerType GetAnalogTriggerTypeForRouting() const = 0;
|
||||
@@ -43,6 +58,16 @@ class InterruptableSensorBase : public ErrorBase, public SendableBase {
|
||||
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.
|
||||
*
|
||||
@@ -119,7 +144,8 @@ class InterruptableSensorBase : public ErrorBase, public SendableBase {
|
||||
virtual void SetUpSourceEdge(bool risingEdge, bool fallingEdge);
|
||||
|
||||
protected:
|
||||
HAL_InterruptHandle m_interrupt = HAL_kInvalidHandle;
|
||||
// atomic for proper destruction
|
||||
std::atomic<HAL_InterruptHandle> m_interrupt{HAL_kInvalidHandle};
|
||||
|
||||
void AllocateInterrupts(bool watcher);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2008-2018 FIRST. All Rights Reserved. */
|
||||
/* Copyright (c) 2008-2019 FIRST. 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. */
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
package edu.wpi.first.wpilibj;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import edu.wpi.first.hal.InterruptJNI;
|
||||
import edu.wpi.first.hal.util.AllocationException;
|
||||
|
||||
@@ -26,6 +28,18 @@ public abstract class InterruptableSensorBase extends SendableBase {
|
||||
WaitResult(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static WaitResult getValue(boolean rising, boolean falling) {
|
||||
if (rising && falling) {
|
||||
return kBoth;
|
||||
} else if (rising) {
|
||||
return kRisingEdge;
|
||||
} else if (falling) {
|
||||
return kFallingEdge;
|
||||
} else {
|
||||
return kTimeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -67,6 +81,36 @@ public abstract class InterruptableSensorBase extends SendableBase {
|
||||
*/
|
||||
public abstract int getPortHandleForRouting();
|
||||
|
||||
/**
|
||||
* Request one of the 8 interrupts asynchronously on this digital input.
|
||||
*
|
||||
* @param handler The {@link InterruptHandler} that contains the method {@link
|
||||
* InterruptHandlerFunction#onInterrupt(boolean, boolean)} that will be called
|
||||
* whenever there is an interrupt on this device. Request interrupts in synchronous
|
||||
* mode where the user program interrupt handler will be called when an interrupt
|
||||
* occurs. The default is interrupt on rising edges only.
|
||||
*/
|
||||
public void requestInterrupts(Consumer<WaitResult> handler) {
|
||||
if (m_interrupt != 0) {
|
||||
throw new AllocationException("The interrupt has already been allocated");
|
||||
}
|
||||
|
||||
allocateInterrupts(false);
|
||||
|
||||
assert m_interrupt != 0;
|
||||
|
||||
InterruptJNI.requestInterrupts(m_interrupt, getPortHandleForRouting(),
|
||||
getAnalogTriggerTypeForRouting());
|
||||
setUpSourceEdge(true, false);
|
||||
InterruptJNI.attachInterruptHandler(m_interrupt, (mask, obj) -> {
|
||||
// Rising edge result is the interrupt bit set in the byte 0xFF
|
||||
// Falling edge result is the interrupt bit set in the byte 0xFF00
|
||||
boolean rising = (mask & 0xFF) != 0;
|
||||
boolean falling = (mask & 0xFF00) != 0;
|
||||
handler.accept(WaitResult.getValue(rising, falling));
|
||||
}, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Request one of the 8 interrupts asynchronously on this digital input.
|
||||
*
|
||||
@@ -154,16 +198,9 @@ public abstract class InterruptableSensorBase extends SendableBase {
|
||||
// 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
|
||||
int rising = ((result & 0xFF) != 0) ? 0x1 : 0x0;
|
||||
int falling = ((result & 0xFF00) != 0) ? 0x0100 : 0x0;
|
||||
result = rising | falling;
|
||||
|
||||
for (WaitResult mode : WaitResult.values()) {
|
||||
if (mode.value == result) {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
boolean rising = (result & 0xFF) != 0;
|
||||
boolean falling = (result & 0xFF00) != 0;
|
||||
return WaitResult.getValue(rising, falling);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user