diff --git a/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java b/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java deleted file mode 100644 index 0ef806e434..0000000000 --- a/hal/src/main/java/edu/wpi/first/hal/InterruptJNI.java +++ /dev/null @@ -1,120 +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. - -package edu.wpi.first.hal; - -/** - * Interrupt HAL JNI functions. - * - * @see "hal/Interrupts.h" - */ -public class InterruptJNI extends JNIWrapper { - /** Invalid handle value. */ - public static final int HalInvalidHandle = 0; - - /** - * Initializes an interrupt. - * - * @return the created interrupt handle - * @see "HAL_InitializeInterrupts" - */ - public static native int initializeInterrupts(); - - /** - * Frees an interrupt. - * - * @param interruptHandle the interrupt handle - * @see "HAL_CleanInterrupts" - */ - public static native void cleanInterrupts(int interruptHandle); - - /** - * Waits for the defined interrupt to occur. - * - * @param interruptHandle the interrupt handle - * @param timeout timeout in seconds - * @param ignorePrevious if true, ignore interrupts that happened before waitForInterrupt was - * called - * @return the mask of interrupts that fired - * @see "HAL_WaitForInterrupt" - */ - public static native long waitForInterrupt( - int interruptHandle, double timeout, boolean ignorePrevious); - - /** - * Waits for any interrupt covered by the mask to occur. - * - * @param interruptHandle the interrupt handle to use for the context - * @param mask the mask of interrupts to wait for - * @param timeout timeout in seconds - * @param ignorePrevious if true, ignore interrupts that happened before waitForInterrupt was - * called - * @return the mask of interrupts that fired - * @see "HAL_WaitForMultipleInterrupts" - */ - public static native long waitForMultipleInterrupts( - int interruptHandle, long mask, double timeout, boolean ignorePrevious); - - /** - * Returns the timestamp for the rising interrupt that occurred most recently. - * - *

This is in the same time domain as getFPGATime(). It only contains the bottom 32 bits of the - * timestamp. If your robot has been running for over 1 hour, you will need to fill in the upper - * 32 bits yourself. - * - * @param interruptHandle the interrupt handle - * @return timestamp in microseconds since FPGA Initialization - */ - public static native long readInterruptRisingTimestamp(int interruptHandle); - - /** - * Returns the timestamp for the falling interrupt that occurred most recently. - * - *

This is in the same time domain as getFPGATime(). It only contains the bottom 32 bits of the - * timestamp. If your robot has been running for over 1 hour, you will need to fill in the upper - * 32 bits yourself. - * - * @param interruptHandle the interrupt handle - * @return timestamp in microseconds since FPGA Initialization - */ - public static native long readInterruptFallingTimestamp(int interruptHandle); - - /** - * Requests interrupts on a specific digital source. - * - * @param interruptHandle the interrupt handle - * @param digitalSourceHandle the digital source handle (either a HAL_AnalogTriggerHandle or a - * HAL_DigitalHandle) - * @param analogTriggerType the trigger type if the source is an AnalogTrigger - * @see "HAL_RequestInterrupts" - */ - public static native void requestInterrupts( - int interruptHandle, int digitalSourceHandle, int analogTriggerType); - - /** - * Sets the edges to trigger the interrupt on. - * - *

Note that both edges triggered is a valid configuration. - * - * @param interruptHandle the interrupt handle - * @param risingEdge true for triggering on rising edge - * @param fallingEdge true for triggering on falling edge - * @see "HAL_SetInterruptUpSourceEdge" - */ - public static native void setInterruptUpSourceEdge( - int interruptHandle, boolean risingEdge, boolean fallingEdge); - - /** - * Releases a waiting interrupt. - * - *

This will release both rising and falling waiters. - * - * @param interruptHandle the interrupt handle to release - * @see "HAL_ReleaseWaitingInterrupt" - */ - public static native void releaseWaitingInterrupt(int interruptHandle); - - /** Utility class. */ - private InterruptJNI() {} -} diff --git a/hal/src/main/native/cpp/jni/InterruptJNI.cpp b/hal/src/main/native/cpp/jni/InterruptJNI.cpp deleted file mode 100644 index 3654cb8ac1..0000000000 --- a/hal/src/main/native/cpp/jni/InterruptJNI.cpp +++ /dev/null @@ -1,173 +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 - -#include -#include -#include - -#include -#include - -#include "HALUtil.h" -#include "edu_wpi_first_hal_InterruptJNI.h" -#include "hal/Interrupts.h" - -using namespace hal; - -extern "C" { - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: initializeInterrupts - * Signature: ()I - */ -JNIEXPORT jint JNICALL -Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts - (JNIEnv* env, jclass) -{ - int32_t status = 0; - HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(&status); - - CheckStatusForceThrow(env, status); - return (jint)interrupt; -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: cleanInterrupts - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts - (JNIEnv* env, jclass, jint interruptHandle) -{ - if (interruptHandle != HAL_kInvalidHandle) { - HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle); - } -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: waitForInterrupt - * Signature: (IDZ)J - */ -JNIEXPORT jlong JNICALL -Java_edu_wpi_first_hal_InterruptJNI_waitForInterrupt - (JNIEnv* env, jclass, jint interruptHandle, jdouble timeout, - jboolean ignorePrevious) -{ - int32_t status = 0; - int64_t result = HAL_WaitForInterrupt((HAL_InterruptHandle)interruptHandle, - timeout, ignorePrevious, &status); - - CheckStatus(env, status); - return result; -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: waitForMultipleInterrupts - * Signature: (IJDZ)J - */ -JNIEXPORT jlong JNICALL -Java_edu_wpi_first_hal_InterruptJNI_waitForMultipleInterrupts - (JNIEnv* env, jclass, jint interruptHandle, jlong mask, jdouble timeout, - jboolean ignorePrevious) -{ - int32_t status = 0; - int64_t result = - HAL_WaitForMultipleInterrupts((HAL_InterruptHandle)interruptHandle, mask, - timeout, ignorePrevious, &status); - - CheckStatus(env, status); - return result; -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: readInterruptRisingTimestamp - * Signature: (I)J - */ -JNIEXPORT jlong JNICALL -Java_edu_wpi_first_hal_InterruptJNI_readInterruptRisingTimestamp - (JNIEnv* env, jclass, jint interruptHandle) -{ - int32_t status = 0; - jlong timeStamp = HAL_ReadInterruptRisingTimestamp( - (HAL_InterruptHandle)interruptHandle, &status); - - CheckStatus(env, status); - return timeStamp; -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: readInterruptFallingTimestamp - * Signature: (I)J - */ -JNIEXPORT jlong JNICALL -Java_edu_wpi_first_hal_InterruptJNI_readInterruptFallingTimestamp - (JNIEnv* env, jclass, jint interruptHandle) -{ - int32_t status = 0; - jlong timeStamp = HAL_ReadInterruptFallingTimestamp( - (HAL_InterruptHandle)interruptHandle, &status); - - CheckStatus(env, status); - return timeStamp; -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: requestInterrupts - * Signature: (III)V - */ -JNIEXPORT void JNICALL -Java_edu_wpi_first_hal_InterruptJNI_requestInterrupts - (JNIEnv* env, jclass, jint interruptHandle, jint digitalSourceHandle, - jint analogTriggerType) -{ - int32_t status = 0; - HAL_RequestInterrupts((HAL_InterruptHandle)interruptHandle, - (HAL_Handle)digitalSourceHandle, - (HAL_AnalogTriggerType)analogTriggerType, &status); - - CheckStatus(env, status); -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: setInterruptUpSourceEdge - * Signature: (IZZ)V - */ -JNIEXPORT void JNICALL -Java_edu_wpi_first_hal_InterruptJNI_setInterruptUpSourceEdge - (JNIEnv* env, jclass, jint interruptHandle, jboolean risingEdge, - jboolean fallingEdge) -{ - int32_t status = 0; - HAL_SetInterruptUpSourceEdge((HAL_InterruptHandle)interruptHandle, risingEdge, - fallingEdge, &status); - - CheckStatus(env, status); -} - -/* - * Class: edu_wpi_first_hal_InterruptJNI - * Method: releaseWaitingInterrupt - * Signature: (I)V - */ -JNIEXPORT void JNICALL -Java_edu_wpi_first_hal_InterruptJNI_releaseWaitingInterrupt - (JNIEnv* env, jclass, jint interruptHandle) -{ - int32_t status = 0; - HAL_ReleaseWaitingInterrupt((HAL_InterruptHandle)interruptHandle, &status); - - CheckStatus(env, status); -} - -} // extern "C" diff --git a/hal/src/main/native/include/hal/HAL.h b/hal/src/main/native/include/hal/HAL.h index 4072b4a64d..d44470ce73 100644 --- a/hal/src/main/native/include/hal/HAL.h +++ b/hal/src/main/native/include/hal/HAL.h @@ -20,7 +20,6 @@ #include "hal/FRCUsageReporting.h" #include "hal/HALBase.h" #include "hal/I2C.h" -#include "hal/Interrupts.h" #include "hal/LEDs.h" #include "hal/Main.h" #include "hal/Notifier.h" diff --git a/hal/src/main/native/include/hal/Interrupts.h b/hal/src/main/native/include/hal/Interrupts.h deleted file mode 100644 index 2bccbe9ce4..0000000000 --- a/hal/src/main/native/include/hal/Interrupts.h +++ /dev/null @@ -1,137 +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 - -#include "hal/AnalogTrigger.h" -#include "hal/Types.h" - -/** - * @defgroup hal_interrupts Interrupts Functions - * @ingroup hal_capi - * @{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Initializes an interrupt. - * - * @param[out] status Error status variable. 0 on success. - * @return the created interrupt handle - */ -HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status); - -/** - * Frees an interrupt. - * - * @param interruptHandle the interrupt handle - */ -void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle); - -/** - * Waits for the defined interrupt to occur. - * - * @param[in] interruptHandle the interrupt handle - * @param[in] timeout timeout in seconds - * @param[in] ignorePrevious if true, ignore interrupts that happened before - * waitForInterrupt was called - * @param[out] status Error status variable. 0 on success. - * @return the mask of interrupts that fired - */ -int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle, - double timeout, HAL_Bool ignorePrevious, - int32_t* status); - -/** - * Waits for any interrupt covered by the mask to occur. - * - * @param[in] interruptHandle the interrupt handle to use for the context - * @param[in] mask the mask of interrupts to wait for - * @param[in] timeout timeout in seconds - * @param[in] ignorePrevious if true, ignore interrupts that happened before - * waitForInterrupt was called - * @param[out] status Error status variable. 0 on success. - * @return the mask of interrupts that fired - */ -int64_t HAL_WaitForMultipleInterrupts(HAL_InterruptHandle interruptHandle, - int64_t mask, double timeout, - HAL_Bool ignorePrevious, int32_t* status); - -/** - * Returns the timestamp for the rising interrupt that occurred most recently. - * - * This is in the same time domain as HAL_GetFPGATime(). It only contains the - * bottom 32 bits of the timestamp. If your robot has been running for over 1 - * hour, you will need to fill in the upper 32 bits yourself. - * - * @param[in] interruptHandle the interrupt handle - * @param[out] status Error status variable. 0 on success. - * @return timestamp in microseconds since FPGA Initialization - */ -int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status); - -/** - * Returns the timestamp for the falling interrupt that occurred most recently. - * - * This is in the same time domain as HAL_GetFPGATime(). It only contains the - * bottom 32 bits of the timestamp. If your robot has been running for over 1 - * hour, you will need to fill in the upper 32 bits yourself. - * - * @param[in] interruptHandle the interrupt handle - * @param[out] status Error status variable. 0 on success. - * @return timestamp in microseconds since FPGA Initialization - */ -int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status); - -/** - * Requests interrupts on a specific digital source. - * - * @param[in] interruptHandle the interrupt handle - * @param[in] digitalSourceHandle the digital source handle (either a - * HAL_AnalogTriggerHandle or a - * HAL_DigitalHandle) - * @param[in] analogTriggerType the trigger type if the source is an - * AnalogTrigger - * @param[out] status Error status variable. 0 on success. - */ -void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle, - HAL_Handle digitalSourceHandle, - HAL_AnalogTriggerType analogTriggerType, - int32_t* status); - -/** - * Sets the edges to trigger the interrupt on. - * - * Note that both edges triggered is a valid configuration. - * - * @param[in] interruptHandle the interrupt handle - * @param[in] risingEdge true for triggering on rising edge - * @param[in] fallingEdge true for triggering on falling edge - * @param[out] status Error status variable. 0 on success. - */ -void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle, - HAL_Bool risingEdge, HAL_Bool fallingEdge, - int32_t* status); - -/** - * Releases a waiting interrupt. - * - * This will release both rising and falling waiters. - * - * @param[in] interruptHandle the interrupt handle to release - * @param[out] status Error status variable. 0 on success. - */ -void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle, - int32_t* status); -#ifdef __cplusplus -} // extern "C" -#endif -/** @} */ diff --git a/hal/src/main/native/sim/HAL.cpp b/hal/src/main/native/sim/HAL.cpp index 26e97c6829..3227d88694 100644 --- a/hal/src/main/native/sim/HAL.cpp +++ b/hal/src/main/native/sim/HAL.cpp @@ -97,7 +97,6 @@ void InitializeHAL() { InitializeEncoder(); InitializeExtensions(); InitializeI2C(); - InitializeInterrupts(); InitializeMain(); InitializeMockHooks(); InitializeNotifier(); diff --git a/hal/src/main/native/sim/HALInitializer.h b/hal/src/main/native/sim/HALInitializer.h index 53841bbe45..359bce8542 100644 --- a/hal/src/main/native/sim/HALInitializer.h +++ b/hal/src/main/native/sim/HALInitializer.h @@ -48,7 +48,6 @@ extern void InitializeEncoder(); extern void InitializeExtensions(); extern void InitializeHAL(); extern void InitializeI2C(); -extern void InitializeInterrupts(); extern void InitializeMain(); extern void InitializeMockHooks(); extern void InitializeNotifier(); diff --git a/hal/src/main/native/sim/Interrupts.cpp b/hal/src/main/native/sim/Interrupts.cpp deleted file mode 100644 index 1537c73640..0000000000 --- a/hal/src/main/native/sim/Interrupts.cpp +++ /dev/null @@ -1,454 +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 "hal/Interrupts.h" - -#include - -#include - -#include "AnalogInternal.h" -#include "DigitalInternal.h" -#include "ErrorsInternal.h" -#include "HALInitializer.h" -#include "MockHooksInternal.h" -#include "PortsInternal.h" -#include "hal/AnalogTrigger.h" -#include "hal/Errors.h" -#include "hal/Value.h" -#include "hal/handles/HandlesInternal.h" -#include "hal/handles/LimitedHandleResource.h" -#include "hal/handles/UnlimitedHandleResource.h" -#include "mockdata/AnalogInDataInternal.h" -#include "mockdata/DIODataInternal.h" - -#ifdef _WIN32 -#pragma warning(disable : 4996 4018 6297 26451 4334) -#endif - -using namespace hal; - -enum WaitResult { - Timeout = 0x0, - RisingEdge = 0x1, - FallingEdge = 0x100, - Both = 0x101, -}; - -namespace { -struct Interrupt { - bool isAnalog; - HAL_Handle portHandle; - uint8_t index; - HAL_AnalogTriggerType trigType; - int64_t risingTimestamp; - int64_t fallingTimestamp; - bool currentState; - bool fireOnUp; - bool fireOnDown; - int32_t callbackId; -}; - -struct SynchronousWaitData { - HAL_InterruptHandle interruptHandle{HAL_kInvalidHandle}; - wpi::condition_variable waitCond; - HAL_Bool waitPredicate{false}; -}; -} // namespace - -static LimitedHandleResource* interruptHandles; - -using SynchronousWaitDataHandle = HAL_Handle; -static UnlimitedHandleResource* - synchronousInterruptHandles; - -namespace hal::init { -void InitializeInterrupts() { - static LimitedHandleResource - iH; - interruptHandles = &iH; - static UnlimitedHandleResource - siH; - synchronousInterruptHandles = &siH; -} -} // namespace hal::init - -extern "C" { -HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) { - hal::init::CheckInit(); - HAL_InterruptHandle handle = interruptHandles->Allocate(); - if (handle == HAL_kInvalidHandle) { - *status = NO_AVAILABLE_RESOURCES; - return HAL_kInvalidHandle; - } - auto anInterrupt = interruptHandles->Get(handle); - if (anInterrupt == nullptr) { // would only occur on thread issue. - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; - } - - anInterrupt->index = getHandleIndex(handle); - anInterrupt->callbackId = -1; - - return handle; -} -void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) { - interruptHandles->Free(interruptHandle); -} - -static void ProcessInterruptDigitalSynchronous(const char* name, void* param, - const struct HAL_Value* value) { - // void* is a SynchronousWaitDataHandle. - // convert to uintptr_t first, then to handle - uintptr_t handleTmp = reinterpret_cast(param); - SynchronousWaitDataHandle handle = - static_cast(handleTmp); - auto interruptData = synchronousInterruptHandles->Get(handle); - if (interruptData == nullptr) { - return; - } - auto interrupt = interruptHandles->Get(interruptData->interruptHandle); - if (interrupt == nullptr) { - return; - } - // Have a valid interrupt - if (value->type != HAL_Type::HAL_BOOLEAN) { - return; - } - bool retVal = value->data.v_boolean; - auto previousState = interrupt->currentState; - interrupt->currentState = retVal; - // If no change in interrupt, return; - if (retVal == previousState) { - return; - } - // If its a falling change, and we dont fire on falling return - if (previousState && !interrupt->fireOnDown) { - return; - } - // If its a rising change, and we dont fire on rising return. - if (!previousState && !interrupt->fireOnUp) { - return; - } - - interruptData->waitPredicate = true; - - // Pulse interrupt - interruptData->waitCond.notify_all(); -} - -static double GetAnalogTriggerValue(HAL_Handle triggerHandle, - HAL_AnalogTriggerType type, - int32_t* status) { - return HAL_GetAnalogTriggerOutput(triggerHandle, type, status); -} - -static void ProcessInterruptAnalogSynchronous(const char* name, void* param, - const struct HAL_Value* value) { - // void* is a SynchronousWaitDataHandle. - // convert to uintptr_t first, then to handle - uintptr_t handleTmp = reinterpret_cast(param); - SynchronousWaitDataHandle handle = - static_cast(handleTmp); - auto interruptData = synchronousInterruptHandles->Get(handle); - if (interruptData == nullptr) { - return; - } - auto interrupt = interruptHandles->Get(interruptData->interruptHandle); - if (interrupt == nullptr) { - return; - } - // Have a valid interrupt - if (value->type != HAL_Type::HAL_DOUBLE) { - return; - } - int32_t status = 0; - bool retVal = GetAnalogTriggerValue(interrupt->portHandle, - interrupt->trigType, &status); - if (status != 0) { - // Interrupt and Cancel - interruptData->waitPredicate = true; - // Pulse interrupt - interruptData->waitCond.notify_all(); - } - auto previousState = interrupt->currentState; - interrupt->currentState = retVal; - // If no change in interrupt, return; - if (retVal == previousState) { - return; - } - // If its a falling change, and we dont fire on falling return - if (previousState && !interrupt->fireOnDown) { - return; - } - // If its a rising change, and we dont fire on rising return. - if (!previousState && !interrupt->fireOnUp) { - return; - } - - interruptData->waitPredicate = true; - - // Pulse interrupt - interruptData->waitCond.notify_all(); -} - -static int64_t WaitForInterruptDigital(HAL_InterruptHandle handle, - Interrupt* interrupt, double timeout, - bool ignorePrevious) { - auto data = std::make_shared(); - - auto dataHandle = synchronousInterruptHandles->Allocate(data); - if (dataHandle == HAL_kInvalidHandle) { - // Error allocating data - return WaitResult::Timeout; - } - - // auto data = synchronousInterruptHandles->Get(dataHandle); - data->waitPredicate = false; - data->interruptHandle = handle; - - int32_t status = 0; - - int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status); - - if (status != 0) { - return WaitResult::Timeout; - } - - interrupt->currentState = SimDIOData[digitalIndex].value; - - int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback( - &ProcessInterruptDigitalSynchronous, - reinterpret_cast(static_cast(dataHandle)), false); - - bool timedOut = false; - - wpi::mutex waitMutex; - - auto timeoutTime = - std::chrono::steady_clock::now() + std::chrono::duration(timeout); - - { - std::unique_lock lock(waitMutex); - while (!data->waitPredicate) { - if (data->waitCond.wait_until(lock, timeoutTime) == - std::cv_status::timeout) { - timedOut = true; - break; - } - } - } - - // Cancel our callback - SimDIOData[digitalIndex].value.CancelCallback(uid); - (void)synchronousInterruptHandles->Free(dataHandle); - - // Check for what to return - if (timedOut) { - return WaitResult::Timeout; - } - // We know the value has changed because we would've timed out otherwise. - // If the current state is true, the previous state was false, so this is a - // rising edge. Otherwise, it's a falling edge. - if (interrupt->currentState) { - // Set our return value and our timestamps - interrupt->risingTimestamp = hal::GetFPGATime(); - return 1 << (interrupt->index); - } else { - interrupt->fallingTimestamp = hal::GetFPGATime(); - return 1 << (8 + interrupt->index); - } -} - -static int64_t WaitForInterruptAnalog(HAL_InterruptHandle handle, - Interrupt* interrupt, double timeout, - bool ignorePrevious) { - auto data = std::make_shared(); - - auto dataHandle = synchronousInterruptHandles->Allocate(data); - if (dataHandle == HAL_kInvalidHandle) { - // Error allocating data - return WaitResult::Timeout; - } - - data->waitPredicate = false; - data->interruptHandle = handle; - - int32_t status = 0; - interrupt->currentState = GetAnalogTriggerValue(interrupt->portHandle, - interrupt->trigType, &status); - - if (status != 0) { - return WaitResult::Timeout; - } - - int32_t analogIndex = - GetAnalogTriggerInputIndex(interrupt->portHandle, &status); - - if (status != 0) { - return WaitResult::Timeout; - } - - int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback( - &ProcessInterruptAnalogSynchronous, - reinterpret_cast(static_cast(dataHandle)), false); - - bool timedOut = false; - - wpi::mutex waitMutex; - - auto timeoutTime = - std::chrono::steady_clock::now() + std::chrono::duration(timeout); - - { - std::unique_lock lock(waitMutex); - while (!data->waitPredicate) { - if (data->waitCond.wait_until(lock, timeoutTime) == - std::cv_status::timeout) { - timedOut = true; - break; - } - } - } - - // Cancel our callback - SimAnalogInData[analogIndex].voltage.CancelCallback(uid); - (void)synchronousInterruptHandles->Free(dataHandle); - - // Check for what to return - if (timedOut) { - return WaitResult::Timeout; - } - // We know the value has changed because we would've timed out otherwise. - // If the current state is true, the previous state was false, so this is a - // rising edge. Otherwise, it's a falling edge. - if (interrupt->currentState) { - // Set our return value and our timestamps - interrupt->risingTimestamp = hal::GetFPGATime(); - return 1 << (interrupt->index); - } else { - interrupt->fallingTimestamp = hal::GetFPGATime(); - return 1 << (8 + interrupt->index); - } -} - -int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle, - double timeout, HAL_Bool ignorePrevious, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return WaitResult::Timeout; - } - - if (interrupt->isAnalog) { - return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout, - ignorePrevious); - } else { - return WaitForInterruptDigital(interruptHandle, interrupt.get(), timeout, - ignorePrevious); - } -} - -int64_t HAL_WaitForMultipleInterrupts(HAL_InterruptHandle interruptHandle, - int64_t mask, double timeout, - HAL_Bool ignorePrevious, - int32_t* status) { - // TODO make this properly work, will require a decent rewrite - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return WaitResult::Timeout; - } - - if (interrupt->isAnalog) { - return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout, - ignorePrevious); - } else { - return WaitForInterruptDigital(interruptHandle, interrupt.get(), timeout, - ignorePrevious); - } -} - -int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return 0; - } - - return interrupt->risingTimestamp; -} -int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return 0; - } - - return interrupt->fallingTimestamp; -} -void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle, - HAL_Handle digitalSourceHandle, - HAL_AnalogTriggerType analogTriggerType, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return; - } - - bool routingAnalogTrigger = false; - uint8_t routingChannel = 0; - uint8_t routingModule = 0; - bool success = - remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel, - routingModule, routingAnalogTrigger); - if (!success) { - *status = HAL_HANDLE_ERROR; - return; - } - - interrupt->isAnalog = routingAnalogTrigger; - interrupt->trigType = analogTriggerType; - interrupt->portHandle = digitalSourceHandle; -} - -void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle, - HAL_Bool risingEdge, HAL_Bool fallingEdge, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return; - } - - interrupt->fireOnDown = fallingEdge; - interrupt->fireOnUp = risingEdge; -} - -void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle, - int32_t* status) { - auto interrupt = interruptHandles->Get(interruptHandle); - if (interrupt == nullptr) { - *status = HAL_HANDLE_ERROR; - return; - } - - synchronousInterruptHandles->ForEach( - [interruptHandle](SynchronousWaitDataHandle handle, - SynchronousWaitData* data) { - if (data->interruptHandle == interruptHandle) { - data->waitPredicate = true; - data->waitCond.notify_all(); - } - }); -} -} // extern "C" diff --git a/hal/src/main/native/systemcore/HAL.cpp b/hal/src/main/native/systemcore/HAL.cpp index 0e347c3bef..5680014f38 100644 --- a/hal/src/main/native/systemcore/HAL.cpp +++ b/hal/src/main/native/systemcore/HAL.cpp @@ -60,7 +60,6 @@ void InitializeHAL() { InitializeEncoder(); InitializeFRCDriverStation(); InitializeI2C(); - InitializeInterrupts(); InitializeLEDs(); InitializeMain(); InitializeNotifier(); diff --git a/hal/src/main/native/systemcore/HALInitializer.h b/hal/src/main/native/systemcore/HALInitializer.h index e4c2d3e83d..913743402a 100644 --- a/hal/src/main/native/systemcore/HALInitializer.h +++ b/hal/src/main/native/systemcore/HALInitializer.h @@ -30,11 +30,9 @@ extern void InitializeDigitalInternal(); extern void InitializeDIO(); extern void InitializeDutyCycle(); extern void InitializeEncoder(); -extern void InitializeFPGAEncoder(); extern void InitializeFRCDriverStation(); extern void InitializeHAL(); extern void InitializeI2C(); -extern void InitializeInterrupts(); extern void InitializeLEDs(); extern void InitializeMain(); extern void InitializeNotifier(); diff --git a/hal/src/main/native/systemcore/Interrupts.cpp b/hal/src/main/native/systemcore/Interrupts.cpp deleted file mode 100644 index c7bff65f8f..0000000000 --- a/hal/src/main/native/systemcore/Interrupts.cpp +++ /dev/null @@ -1,83 +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 "hal/Interrupts.h" - -#include - -#include - -#include "HALInitializer.h" -#include "HALInternal.h" -#include "PortsInternal.h" -#include "hal/Errors.h" -#include "hal/HALBase.h" -#include "hal/handles/HandlesInternal.h" -#include "hal/handles/LimitedHandleResource.h" - -using namespace hal; - -namespace hal::init { -void InitializeInterrupts() {} -} // namespace hal::init - -extern "C" { - -HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) { - hal::init::CheckInit(); - *status = HAL_HANDLE_ERROR; - return HAL_kInvalidHandle; -} - -void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {} - -int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle, - double timeout, HAL_Bool ignorePrevious, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return 0; -} - -int64_t HAL_WaitForMultipleInterrupts(HAL_InterruptHandle interruptHandle, - int64_t mask, double timeout, - HAL_Bool ignorePrevious, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return 0; -} - -int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return 0; -} - -int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return 0; -} - -void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle, - HAL_Handle digitalSourceHandle, - HAL_AnalogTriggerType analogTriggerType, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return; -} - -void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle, - HAL_Bool risingEdge, HAL_Bool fallingEdge, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return; -} - -void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle, - int32_t* status) { - *status = HAL_HANDLE_ERROR; - return; -} - -} // extern "C" diff --git a/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp b/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp deleted file mode 100644 index 20fc761c27..0000000000 --- a/wpilibc/src/main/native/cpp/AsynchronousInterrupt.cpp +++ /dev/null @@ -1,70 +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/AsynchronousInterrupt.h" - -#include - -#include -#include - -using namespace frc; - -AsynchronousInterrupt::AsynchronousInterrupt( - DigitalSource& source, std::function callback) - : m_interrupt{source}, m_callback{std::move(callback)} {} -AsynchronousInterrupt::AsynchronousInterrupt( - DigitalSource* source, std::function callback) - : m_interrupt{source}, m_callback{std::move(callback)} {} -AsynchronousInterrupt::AsynchronousInterrupt( - std::shared_ptr source, - std::function 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(); -} diff --git a/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp b/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp deleted file mode 100644 index 084efd9d1f..0000000000 --- a/wpilibc/src/main/native/cpp/SynchronousInterrupt.cpp +++ /dev/null @@ -1,103 +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/SynchronousInterrupt.h" - -#include -#include -#include - -#include -#include - -#include "frc/DigitalSource.h" -#include "frc/Errors.h" - -using namespace frc; - -SynchronousInterrupt::SynchronousInterrupt(DigitalSource& source) - : m_source{&source, wpi::NullDeleter()} { - InitSynchronousInterrupt(); -} -SynchronousInterrupt::SynchronousInterrupt(DigitalSource* source) - : m_source{source, wpi::NullDeleter()} { - if (m_source == nullptr) { - FRC_CheckErrorStatus(frc::err::NullParameter, "Source is null"); - } else { - InitSynchronousInterrupt(); - } -} -SynchronousInterrupt::SynchronousInterrupt( - std::shared_ptr 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( - 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"); -} - -inline SynchronousInterrupt::WaitResult operator|( - SynchronousInterrupt::WaitResult lhs, - SynchronousInterrupt::WaitResult rhs) { - using T = std::underlying_type_t; - return static_cast(static_cast(lhs) | - static_cast(rhs)); -} - -SynchronousInterrupt::WaitResult SynchronousInterrupt::WaitForInterrupt( - units::second_t timeout, bool ignorePrevious) { - int32_t status = 0; - auto result = - HAL_WaitForInterrupt(m_handle, timeout.value(), 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(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(ts)}; - return ms; -} diff --git a/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h b/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h deleted file mode 100644 index 0dea5bc8e7..0000000000 --- a/wpilibc/src/main/native/include/frc/AsynchronousInterrupt.h +++ /dev/null @@ -1,180 +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 - -#include -#include -#include -#include -#include - -#include - -namespace frc { -/** - * Class for handling asynchronous interrupts using a callback thread. - * - *

By default, interrupts will occur on rising edge. Callbacks are disabled - * by default, and Enable() must be called before they will occur. - * - *

Both rising and falling edges can be indicated in one callback if both a - * rising and falling edge occurred since the previous callback. - * - *

Synchronous (blocking) interrupts are handled by the SynchronousInterrupt - * class. - */ -class AsynchronousInterrupt { - public: - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - *

The first bool in the callback indicates the rising edge triggered the - * interrupt, the second bool is falling edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param callback the callback function to call when the interrupt is - * triggered - */ - AsynchronousInterrupt(DigitalSource& source, - std::function callback); - - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - *

The first bool in the callback indicates the rising edge triggered the - * interrupt, the second bool is falling edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param callback the callback function to call when the interrupt is - * triggered - */ - AsynchronousInterrupt(DigitalSource* source, - std::function callback); - - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - *

The first bool in the callback indicates the rising edge triggered the - * interrupt, the second bool is falling edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param callback the callback function to call when the interrupt is - * triggered - */ - AsynchronousInterrupt(std::shared_ptr source, - std::function callback); - - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param f the callback function to call when the interrupt is triggered - * @param arg the first argument, interrupt was triggered on rising edge - * @param args the remaining arguments, interrupt was triggered on falling - * edge - */ - template - AsynchronousInterrupt(DigitalSource& source, Callable&& f, Arg&& arg, - Args&&... args) - : AsynchronousInterrupt( - source, std::bind(std::forward(f), std::forward(arg), - std::forward(args)...)) {} - - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param f the callback function to call when the interrupt is triggered - * @param arg the first argument, interrupt was triggered on rising edge - * @param args the remaining arguments, interrupt was triggered on falling - * edge - */ - template - AsynchronousInterrupt(DigitalSource* source, Callable&& f, Arg&& arg, - Args&&... args) - : AsynchronousInterrupt( - source, std::bind(std::forward(f), std::forward(arg), - std::forward(args)...)) {} - - /** - * Construct an Asynchronous Interrupt from a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - * @param source the DigitalSource the interrupts are triggered from - * @param f the callback function to call when the interrupt is triggered - * @param arg the first argument, interrupt was triggered on rising edge - * @param args the remaining arguments, interrupt was triggered on falling - * edge - */ - template - AsynchronousInterrupt(std::shared_ptr source, Callable&& f, - Arg&& arg, Args&&... args) - : AsynchronousInterrupt( - source, std::bind(std::forward(f), std::forward(arg), - std::forward(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. - * - *

This function does not require the interrupt to be enabled to work. - * - *

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. - * - *

This function does not require the interrupt to be enabled to work. - * - *

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 m_callback; -}; -} // namespace frc diff --git a/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h b/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h deleted file mode 100644 index 15ce7fb6cd..0000000000 --- a/wpilibc/src/main/native/include/frc/SynchronousInterrupt.h +++ /dev/null @@ -1,112 +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 - -#include -#include -#include - -namespace frc { -class DigitalSource; - -/** - * Class for handling synchronous (blocking) interrupts. - * - *

By default, interrupts will occur on rising edge. - * - *

Asynchronous interrupts are handled by the AsynchronousInterrupt class. - */ -class SynchronousInterrupt { - public: - /** - * Event trigger combinations for a synchronous interrupt. - */ - enum WaitResult { - /// Timeout event. - kTimeout = 0x0, - /// Rising edge event. - kRisingEdge = 0x1, - /// Falling edge event. - kFallingEdge = 0x100, - /// Both rising and falling edge events. - kBoth = 0x101, - }; - - /** - * Construct a Synchronous Interrupt from a Digital Source. - * - * @param source the DigitalSource the interrupts are triggered from - */ - explicit SynchronousInterrupt(DigitalSource& source); - - /** - * Construct a Synchronous Interrupt from a Digital Source. - * - * @param source the DigitalSource the interrupts are triggered from - */ - explicit SynchronousInterrupt(DigitalSource* source); - - /** - * Construct a Synchronous Interrupt from a Digital Source. - * - * @param source the DigitalSource the interrupts are triggered from - */ - explicit SynchronousInterrupt(std::shared_ptr source); - - SynchronousInterrupt(SynchronousInterrupt&&) = default; - SynchronousInterrupt& operator=(SynchronousInterrupt&&) = default; - - /** - * Wait for an interrupt to occur. - * - *

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 occurred 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. - * - * @return the timestamp in seconds relative to getFPGATime - */ - units::second_t GetRisingTimestamp(); - - /** - * Get the timestamp of the last falling edge. - * - *

This function does not require the interrupt to be enabled to work. - * - *

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 m_source; - hal::Handle m_handle; -}; -} // namespace frc diff --git a/wpilibc/src/test/native/cpp/InterruptTest.cpp b/wpilibc/src/test/native/cpp/InterruptTest.cpp deleted file mode 100644 index 8b054d75f5..0000000000 --- a/wpilibc/src/test/native/cpp/InterruptTest.cpp +++ /dev/null @@ -1,103 +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 - -#include -#include - -#include "frc/AsynchronousInterrupt.h" -#include "frc/DigitalInput.h" -#include "frc/Timer.h" -#include "frc/simulation/DIOSim.h" - -namespace frc { -using namespace frc::sim; -TEST(InterruptTest, AsynchronousInterrupt) { - HAL_Initialize(500, 0); - - std::atomic_int counter{0}; - std::atomic_bool hasFired{false}; - - DigitalInput di{0}; - AsynchronousInterrupt interrupt{di, [&](bool rising, bool falling) { - counter++; - hasFired = true; - }}; - - interrupt.Enable(); - frc::Wait(0.5_s); - DIOSim digitalSim{di}; - digitalSim.SetValue(false); - frc::Wait(20_ms); - digitalSim.SetValue(true); - frc::Wait(20_ms); - - int count = 0; - while (!hasFired) { - frc::Wait(5_ms); - count++; - ASSERT_TRUE(count < 1000); - } - ASSERT_EQ(1, counter.load()); -} - -TEST(InterruptTest, RisingEdge) { - HAL_Initialize(500, 0); - - std::atomic_bool hasFiredFallingEdge{false}; - std::atomic_bool hasFiredRisingEdge{false}; - - DigitalInput di{0}; - AsynchronousInterrupt interrupt{di, [&](bool rising, bool falling) { - hasFiredFallingEdge = falling; - hasFiredRisingEdge = rising; - }}; - interrupt.SetInterruptEdges(true, true); - DIOSim digitalSim{di}; - digitalSim.SetValue(false); - interrupt.Enable(); - frc::Wait(0.5_s); - digitalSim.SetValue(true); - frc::Wait(20_ms); - - int count = 0; - while (!hasFiredRisingEdge) { - frc::Wait(5_ms); - count++; - ASSERT_TRUE(count < 1000); - } - EXPECT_FALSE(hasFiredFallingEdge); - EXPECT_TRUE(hasFiredRisingEdge); -} - -TEST(InterruptTest, FallingEdge) { - HAL_Initialize(500, 0); - - std::atomic_bool hasFiredFallingEdge{false}; - std::atomic_bool hasFiredRisingEdge{false}; - - DigitalInput di{0}; - AsynchronousInterrupt interrupt{di, [&](bool rising, bool falling) { - hasFiredFallingEdge = falling; - hasFiredRisingEdge = rising; - }}; - interrupt.SetInterruptEdges(true, true); - DIOSim digitalSim{di}; - digitalSim.SetValue(true); - interrupt.Enable(); - frc::Wait(0.5_s); - digitalSim.SetValue(false); - frc::Wait(20_ms); - - int count = 0; - while (!hasFiredFallingEdge) { - frc::Wait(5_ms); - count++; - ASSERT_TRUE(count < 1000); - } - EXPECT_TRUE(hasFiredFallingEdge); - EXPECT_FALSE(hasFiredRisingEdge); -} -} // namespace frc diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java deleted file mode 100644 index f64284f61a..0000000000 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/AsynchronousInterrupt.java +++ /dev/null @@ -1,155 +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. - -package edu.wpi.first.wpilibj; - -import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; - -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.function.BiConsumer; - -/** - * Class for handling asynchronous interrupts using a callback thread. - * - *

By default, interrupts will occur on rising edge. Callbacks are disabled by default, and - * enable() must be called before they will occur. - * - *

Both rising and falling edges can be indicated in one callback if both a rising and falling - * edge occurred since the previous callback. - * - *

Synchronous (blocking) interrupts are handled by the SynchronousInterrupt class. - */ -public class AsynchronousInterrupt implements AutoCloseable { - private final BiConsumer m_callback; - private final SynchronousInterrupt m_interrupt; - - private final AtomicBoolean m_keepRunning = new AtomicBoolean(false); - private Thread m_thread; - - /** - * Construct a new asynchronous interrupt using a Digital Source. - * - *

At construction, the interrupt will trigger on the rising edge. - * - *

Callbacks will not be triggered until enable() is called. - * - *

The first bool in the callback indicates the rising edge triggered the interrupt, the second - * bool is falling edge. - * - * @param source The digital source to use. - * @param callback The callback to call on an interrupt - */ - public AsynchronousInterrupt(DigitalSource source, BiConsumer callback) { - m_callback = requireNonNullParam(callback, "callback", "AsynchronousInterrupt"); - m_interrupt = new SynchronousInterrupt(source); - } - - /** - * Closes the interrupt. - * - *

This does not close the associated digital source. - * - *

This will disable the interrupt if it is enabled. - */ - @Override - public void close() { - disable(); - m_interrupt.close(); - } - - /** - * Enables interrupt callbacks. Before this, callbacks will not occur. Does nothing if already - * enabled. - */ - public void enable() { - if (m_keepRunning.get()) { - return; - } - - m_keepRunning.set(true); - m_thread = new Thread(this::threadMain); - m_thread.start(); - } - - /** Disables interrupt callbacks. Does nothing if already disabled. */ - public void disable() { - m_keepRunning.set(false); - m_interrupt.wakeupWaitingInterrupt(); - if (m_thread != null) { - if (m_thread.isAlive()) { - try { - m_thread.interrupt(); - m_thread.join(); - } catch (InterruptedException ex) { - Thread.currentThread().interrupt(); - } - } - m_thread = null; - } - } - - /** - * Set which edges to trigger the interrupt on. - * - * @param risingEdge Trigger on rising edge - * @param fallingEdge Trigger on falling edge - */ - public void setInterruptEdges(boolean risingEdge, boolean fallingEdge) { - m_interrupt.setInterruptEdges(risingEdge, fallingEdge); - } - - /** - * Get the timestamp of the last rising edge. - * - *

This function does not require the interrupt to be enabled to work. - * - *

This only works if rising edge was configured using setInterruptEdges. - * - * @return the timestamp in seconds relative to getFPGATime - */ - public double getRisingTimestamp() { - return m_interrupt.getRisingTimestamp(); - } - - /** - * Get the timestamp of the last falling edge. - * - *

This function does not require the interrupt to be enabled to work. - * - *

This only works if falling edge was configured using setInterruptEdges. - * - * @return the timestamp in seconds relative to getFPGATime - */ - public double getFallingTimestamp() { - return m_interrupt.getFallingTimestamp(); - } - - private void threadMain() { - while (m_keepRunning.get()) { - var result = m_interrupt.waitForInterrupt(10, false); - if (!m_keepRunning.get()) { - break; - } - boolean rising = false; - boolean falling = false; - switch (result) { - case kBoth -> { - rising = true; - falling = true; - } - case kFallingEdge -> { - falling = true; - } - case kRisingEdge -> { - rising = true; - } - default -> { - continue; - } - } - - m_callback.accept(rising, falling); - } - } -} diff --git a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java b/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java deleted file mode 100644 index 449402c6cd..0000000000 --- a/wpilibj/src/main/java/edu/wpi/first/wpilibj/SynchronousInterrupt.java +++ /dev/null @@ -1,154 +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. - -package edu.wpi.first.wpilibj; - -import static edu.wpi.first.util.ErrorMessages.requireNonNullParam; - -import edu.wpi.first.hal.InterruptJNI; - -/** - * Class for handling synchronous (blocking) interrupts. - * - *

By default, interrupts will occur on rising edge. - * - *

Asynchronous interrupts are handled by the AsynchronousInterrupt class. - */ -public class SynchronousInterrupt implements AutoCloseable { - @SuppressWarnings("PMD.SingularField") - private final DigitalSource m_source; - - private final int m_handle; - - /** Event trigger combinations for a synchronous interrupt. */ - public enum WaitResult { - /** Timeout event. */ - kTimeout(0x0), - /** Rising edge event. */ - kRisingEdge(0x1), - /** Falling edge event. */ - kFallingEdge(0x100), - /** Both rising and falling edge events. */ - kBoth(0x101); - - /** WaitResult value. */ - public final int value; - - WaitResult(int value) { - this.value = value; - } - - /** - * Create a wait result enum. - * - * @param rising True if a rising edge occurred. - * @param falling True if a falling edge occurred. - * @return A wait result enum. - */ - 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; - } - } - } - - /** - * Constructs a new synchronous interrupt using a DigitalSource. - * - *

At construction, the interrupt will trigger on the rising edge. - * - * @param source The digital source to use. - */ - public SynchronousInterrupt(DigitalSource source) { - m_source = requireNonNullParam(source, "source", "SynchronousInterrupt"); - m_handle = InterruptJNI.initializeInterrupts(); - InterruptJNI.requestInterrupts( - m_handle, m_source.getPortHandleForRouting(), m_source.getAnalogTriggerTypeForRouting()); - InterruptJNI.setInterruptUpSourceEdge(m_handle, true, false); - } - - /** - * Closes the interrupt. - * - *

This does not close the associated digital source. - */ - @Override - public void close() { - InterruptJNI.cleanInterrupts(m_handle); - } - - /** - * Wait for an interrupt. - * - * @param timeoutSeconds The timeout in seconds. 0 or less will return immediately. - * @param ignorePrevious True to ignore if a previous interrupt has occurred, and only wait for a - * new trigger. False will consider if an interrupt has occurred since the last time the - * interrupt was read. - * @return Result of which edges were triggered, or if a timeout occurred. - */ - public WaitResult waitForInterrupt(double timeoutSeconds, boolean ignorePrevious) { - long result = InterruptJNI.waitForInterrupt(m_handle, timeoutSeconds, ignorePrevious); - - // 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 then conduct a logical AND on the 2 results - // together to match the existing enum for all interrupts - boolean rising = (result & 0xFF) != 0; - boolean falling = (result & 0xFF00) != 0; - return WaitResult.getValue(rising, falling); - } - - /** - * Wait for an interrupt, ignoring any previously occurring interrupts. - * - * @param timeoutSeconds The timeout in seconds. 0 or less will return immediately. - * @return Result of which edges were triggered, or if a timeout occurred. - */ - public WaitResult waitForInterrupt(double timeoutSeconds) { - return waitForInterrupt(timeoutSeconds, true); - } - - /** - * Set which edges to trigger the interrupt on. - * - * @param risingEdge Trigger on rising edge - * @param fallingEdge Trigger on falling edge - */ - public void setInterruptEdges(boolean risingEdge, boolean fallingEdge) { - InterruptJNI.setInterruptUpSourceEdge(m_handle, risingEdge, fallingEdge); - } - - /** - * Get the timestamp of the last rising edge. - * - *

This only works if rising edge was configured using setInterruptEdges. - * - * @return the timestamp in seconds relative to getFPGATime - */ - public double getRisingTimestamp() { - return InterruptJNI.readInterruptRisingTimestamp(m_handle) * 1e-6; - } - - /** - * Get the timestamp of the last falling edge. - * - *

This only works if falling edge was configured using setInterruptEdges. - * - * @return the timestamp in seconds relative to getFPGATime - */ - public double getFallingTimestamp() { - return InterruptJNI.readInterruptFallingTimestamp(m_handle) * 1e-6; - } - - /** Force triggering of any waiting interrupt, which will be seen as a timeout. */ - public void wakeupWaitingInterrupt() { - InterruptJNI.releaseWaitingInterrupt(m_handle); - } -} diff --git a/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java b/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java deleted file mode 100644 index 7855d89753..0000000000 --- a/wpilibj/src/test/java/edu/wpi/first/wpilibj/InterruptTest.java +++ /dev/null @@ -1,120 +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. - -package edu.wpi.first.wpilibj; - -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import edu.wpi.first.wpilibj.simulation.DIOSim; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; -import org.junit.jupiter.api.Test; - -class InterruptTest { - @Test - void testAsynchronousInterrupt() { - AtomicBoolean hasFired = new AtomicBoolean(false); - AtomicInteger counter = new AtomicInteger(0); - - try (DigitalInput di = new DigitalInput(0); - AsynchronousInterrupt interrupt = - new AsynchronousInterrupt( - di, - (rising, falling) -> { - counter.incrementAndGet(); - hasFired.set(true); - })) { - interrupt.enable(); - Timer.delay(0.5); - DIOSim digitalSim = new DIOSim(di); - digitalSim.setValue(false); - Timer.delay(0.02); - digitalSim.setValue(true); - Timer.delay(0.02); - - int count = 0; - while (!hasFired.get()) { - Timer.delay(0.005); - count++; - assertTrue(count < 1000); - } - assertEquals(1, counter.get(), "The interrupt did not fire the expected number of times"); - } - } - - @Test - void testRisingEdge() { - AtomicBoolean hasFiredFallingEdge = new AtomicBoolean(false); - AtomicBoolean hasFiredRisingEdge = new AtomicBoolean(false); - - try (DigitalInput di = new DigitalInput(0); - AsynchronousInterrupt interrupt = - new AsynchronousInterrupt( - di, - (rising, falling) -> { - hasFiredFallingEdge.set(falling); - hasFiredRisingEdge.set(rising); - })) { - interrupt.setInterruptEdges(true, true); - DIOSim digitalSim = new DIOSim(di); - digitalSim.setValue(false); - interrupt.enable(); - Timer.delay(0.5); - digitalSim.setValue(true); - Timer.delay(0.02); - - int count = 0; - while (!hasFiredRisingEdge.get()) { - Timer.delay(0.005); - count++; - assertTrue(count < 1000); - } - assertAll( - () -> - assertFalse(hasFiredFallingEdge.get(), "The interrupt triggered on the falling edge"), - () -> - assertTrue( - hasFiredRisingEdge.get(), "The interrupt did not trigger on the rising edge")); - } - } - - @Test - void testFallingEdge() { - AtomicBoolean hasFiredFallingEdge = new AtomicBoolean(false); - AtomicBoolean hasFiredRisingEdge = new AtomicBoolean(false); - - try (DigitalInput di = new DigitalInput(0); - AsynchronousInterrupt interrupt = - new AsynchronousInterrupt( - di, - (rising, falling) -> { - hasFiredFallingEdge.set(falling); - hasFiredRisingEdge.set(rising); - })) { - interrupt.setInterruptEdges(true, true); - DIOSim digitalSim = new DIOSim(di); - digitalSim.setValue(true); - interrupt.enable(); - Timer.delay(0.5); - digitalSim.setValue(false); - Timer.delay(0.02); - - int count = 0; - while (!hasFiredFallingEdge.get()) { - Timer.delay(0.005); - count++; - assertTrue(count < 1000); - } - assertAll( - () -> - assertTrue( - hasFiredFallingEdge.get(), "The interrupt did not trigger on the rising edge"), - () -> - assertFalse(hasFiredRisingEdge.get(), "The interrupt triggered on the rising edge")); - } - } -}