mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-22 01:11:42 +00:00
[wpilib] Remove InterruptableSensorBase and replace with interrupt classes (#2410)
This commit is contained in:
@@ -21,65 +21,14 @@
|
||||
using namespace hal;
|
||||
|
||||
namespace {
|
||||
// Safe thread to allow callbacks to run on their own thread
|
||||
class InterruptThread : public wpi::SafeThread {
|
||||
public:
|
||||
void Main() override {
|
||||
std::unique_lock lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !m_active || m_notify; });
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
m_notify = false;
|
||||
HAL_InterruptHandlerFunction handler = m_handler;
|
||||
uint32_t mask = m_mask;
|
||||
void* param = m_param;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
handler(mask, param);
|
||||
lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
bool m_notify = false;
|
||||
HAL_InterruptHandlerFunction m_handler;
|
||||
void* m_param;
|
||||
uint32_t m_mask;
|
||||
};
|
||||
|
||||
class InterruptThreadOwner : public wpi::SafeThreadOwner<InterruptThread> {
|
||||
public:
|
||||
void SetFunc(HAL_InterruptHandlerFunction handler, void* param) {
|
||||
auto thr = GetThread();
|
||||
if (!thr)
|
||||
return;
|
||||
thr->m_handler = handler;
|
||||
thr->m_param = param;
|
||||
}
|
||||
|
||||
void Notify(uint32_t mask) {
|
||||
auto thr = GetThread();
|
||||
if (!thr)
|
||||
return;
|
||||
thr->m_mask = mask;
|
||||
thr->m_notify = true;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct Interrupt {
|
||||
std::unique_ptr<tInterrupt> anInterrupt;
|
||||
std::unique_ptr<tInterruptManager> manager;
|
||||
std::unique_ptr<InterruptThreadOwner> threadOwner = nullptr;
|
||||
void* param = nullptr;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
static void threadedInterruptHandler(uint32_t mask, void* param) {
|
||||
static_cast<InterruptThreadOwner*>(param)->Notify(mask);
|
||||
}
|
||||
|
||||
static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
|
||||
HAL_HandleEnum::Interrupt>* interruptHandles;
|
||||
|
||||
@@ -94,8 +43,7 @@ void InitializeInterrupts() {
|
||||
|
||||
extern "C" {
|
||||
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
|
||||
int32_t* status) {
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
|
||||
hal::init::CheckInit();
|
||||
HAL_InterruptHandle handle = interruptHandles->Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
@@ -108,24 +56,16 @@ HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
|
||||
anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
|
||||
anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
|
||||
anInterrupt->manager = std::make_unique<tInterruptManager>(
|
||||
(1u << interruptIndex) | (1u << (interruptIndex + 8u)), watcher, status);
|
||||
(1u << interruptIndex) | (1u << (interruptIndex + 8u)), true, status);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
interruptHandles->Free(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
return nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
if (anInterrupt->manager->isEnabled(status)) {
|
||||
anInterrupt->manager->disable(status);
|
||||
}
|
||||
|
||||
void* param = anInterrupt->param;
|
||||
return param;
|
||||
}
|
||||
|
||||
int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
@@ -150,31 +90,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
return result;
|
||||
}
|
||||
|
||||
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!anInterrupt->manager->isEnabled(status)) {
|
||||
anInterrupt->manager->enable(status);
|
||||
}
|
||||
}
|
||||
|
||||
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
if (anInterrupt->manager->isEnabled(status)) {
|
||||
anInterrupt->manager->disable(status);
|
||||
}
|
||||
}
|
||||
|
||||
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
@@ -223,40 +138,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
|
||||
}
|
||||
|
||||
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
anInterrupt->manager->registerHandler(handler, param, status);
|
||||
anInterrupt->param = param;
|
||||
}
|
||||
|
||||
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interrupt_handle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
auto anInterrupt = interruptHandles->Get(interrupt_handle);
|
||||
if (anInterrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
anInterrupt->threadOwner = std::make_unique<InterruptThreadOwner>();
|
||||
anInterrupt->threadOwner->Start();
|
||||
anInterrupt->threadOwner->SetFunc(handler, param);
|
||||
|
||||
HAL_AttachInterruptHandler(interrupt_handle, threadedInterruptHandler,
|
||||
anInterrupt->threadOwner.get(), status);
|
||||
|
||||
if (*status != 0) {
|
||||
anInterrupt->threadOwner = nullptr;
|
||||
}
|
||||
anInterrupt->param = param;
|
||||
}
|
||||
|
||||
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
int32_t* status) {
|
||||
|
||||
@@ -17,126 +17,19 @@
|
||||
|
||||
using namespace hal;
|
||||
|
||||
// Thread where callbacks are actually performed.
|
||||
//
|
||||
// JNI's AttachCurrentThread() creates a Java Thread object on every
|
||||
// invocation, which is both time inefficient and causes issues with Eclipse
|
||||
// (which tries to keep a thread list up-to-date and thus gets swamped).
|
||||
//
|
||||
// Instead, this class attaches just once. When a hardware notification
|
||||
// occurs, a condition variable wakes up this thread and this thread actually
|
||||
// makes the call into Java.
|
||||
//
|
||||
// We don't want to use a FIFO here. If the user code takes too long to
|
||||
// process, we will just ignore the redundant wakeup.
|
||||
class InterruptThreadJNI : public wpi::SafeThread {
|
||||
public:
|
||||
void Main() override;
|
||||
|
||||
bool m_notify = false;
|
||||
uint32_t m_mask = 0;
|
||||
jobject m_func = nullptr;
|
||||
jmethodID m_mid;
|
||||
jobject m_param = nullptr;
|
||||
};
|
||||
|
||||
class InterruptJNI : public wpi::SafeThreadOwner<InterruptThreadJNI> {
|
||||
public:
|
||||
void SetFunc(JNIEnv* env, jobject func, jmethodID mid, jobject param);
|
||||
|
||||
void Notify(uint32_t mask) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
thr->m_notify = true;
|
||||
thr->m_mask = mask;
|
||||
thr->m_cond.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
void InterruptJNI::SetFunc(JNIEnv* env, jobject func, jmethodID mid,
|
||||
jobject param) {
|
||||
auto thr = GetThread();
|
||||
if (!thr) {
|
||||
return;
|
||||
}
|
||||
// free global references
|
||||
if (thr->m_func) {
|
||||
env->DeleteGlobalRef(thr->m_func);
|
||||
}
|
||||
if (thr->m_param) {
|
||||
env->DeleteGlobalRef(thr->m_param);
|
||||
}
|
||||
// create global references
|
||||
thr->m_func = env->NewGlobalRef(func);
|
||||
thr->m_param = param ? env->NewGlobalRef(param) : nullptr;
|
||||
thr->m_mid = mid;
|
||||
}
|
||||
|
||||
void InterruptThreadJNI::Main() {
|
||||
JNIEnv* env;
|
||||
JavaVMAttachArgs args;
|
||||
args.version = JNI_VERSION_1_2;
|
||||
args.name = const_cast<char*>("Interrupt");
|
||||
args.group = nullptr;
|
||||
jint rs = GetJVM()->AttachCurrentThreadAsDaemon(
|
||||
reinterpret_cast<void**>(&env), &args);
|
||||
if (rs != JNI_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::unique_lock lock(m_mutex);
|
||||
while (m_active) {
|
||||
m_cond.wait(lock, [&] { return !m_active || m_notify; });
|
||||
if (!m_active) {
|
||||
break;
|
||||
}
|
||||
m_notify = false;
|
||||
if (!m_func) {
|
||||
continue;
|
||||
}
|
||||
jobject func = m_func;
|
||||
jmethodID mid = m_mid;
|
||||
uint32_t mask = m_mask;
|
||||
jobject param = m_param;
|
||||
lock.unlock(); // don't hold mutex during callback execution
|
||||
env->CallVoidMethod(func, mid, static_cast<jint>(mask), param);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
env->ExceptionClear();
|
||||
}
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
// free global references
|
||||
if (m_func) {
|
||||
env->DeleteGlobalRef(m_func);
|
||||
}
|
||||
if (m_param) {
|
||||
env->DeleteGlobalRef(m_param);
|
||||
}
|
||||
|
||||
GetJVM()->DetachCurrentThread();
|
||||
}
|
||||
|
||||
void interruptHandler(uint32_t mask, void* param) {
|
||||
static_cast<InterruptJNI*>(param)->Notify(mask);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: initializeInterrupts
|
||||
* Signature: (Z)I
|
||||
* Signature: ()I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_edu_wpi_first_hal_InterruptJNI_initializeInterrupts
|
||||
(JNIEnv* env, jclass, jboolean watcher)
|
||||
(JNIEnv* env, jclass)
|
||||
{
|
||||
int32_t status = 0;
|
||||
HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(watcher, &status);
|
||||
HAL_InterruptHandle interrupt = HAL_InitializeInterrupts(&status);
|
||||
|
||||
CheckStatusForceThrow(env, status);
|
||||
return (jint)interrupt;
|
||||
@@ -151,14 +44,7 @@ JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_InterruptJNI_cleanInterrupts
|
||||
(JNIEnv* env, jclass, jint interruptHandle)
|
||||
{
|
||||
int32_t status = 0;
|
||||
auto param =
|
||||
HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
||||
if (param) {
|
||||
delete static_cast<InterruptJNI*>(param);
|
||||
}
|
||||
|
||||
// ignore status, as an invalid handle just needs to be ignored.
|
||||
HAL_CleanInterrupts((HAL_InterruptHandle)interruptHandle);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -179,36 +65,6 @@ Java_edu_wpi_first_hal_InterruptJNI_waitForInterrupt
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: enableInterrupts
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_InterruptJNI_enableInterrupts
|
||||
(JNIEnv* env, jclass, jint interruptHandle)
|
||||
{
|
||||
int32_t status = 0;
|
||||
HAL_EnableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
||||
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: disableInterrupts
|
||||
* Signature: (I)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_InterruptJNI_disableInterrupts
|
||||
(JNIEnv* env, jclass, jint interruptHandle)
|
||||
{
|
||||
int32_t status = 0;
|
||||
HAL_DisableInterrupts((HAL_InterruptHandle)interruptHandle, &status);
|
||||
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: readInterruptRisingTimestamp
|
||||
@@ -261,37 +117,6 @@ Java_edu_wpi_first_hal_InterruptJNI_requestInterrupts
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: attachInterruptHandler
|
||||
* Signature: (ILjava/lang/Object;Ljava/lang/Object;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_hal_InterruptJNI_attachInterruptHandler
|
||||
(JNIEnv* env, jclass, jint interruptHandle, jobject handler, jobject param)
|
||||
{
|
||||
jclass cls = env->GetObjectClass(handler);
|
||||
if (cls == nullptr) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
jmethodID mid = env->GetMethodID(cls, "apply", "(ILjava/lang/Object;)V");
|
||||
if (mid == nullptr) {
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
InterruptJNI* intr = new InterruptJNI;
|
||||
intr->Start();
|
||||
intr->SetFunc(env, handler, mid, param);
|
||||
|
||||
int32_t status = 0;
|
||||
HAL_AttachInterruptHandler((HAL_InterruptHandle)interruptHandle,
|
||||
interruptHandler, intr, &status);
|
||||
|
||||
CheckStatus(env, status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_hal_InterruptJNI
|
||||
* Method: setInterruptUpSourceEdge
|
||||
|
||||
@@ -19,25 +19,20 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*HAL_InterruptHandlerFunction)(uint32_t interruptAssertedMask,
|
||||
void* param);
|
||||
|
||||
/**
|
||||
* Initializes an interrupt.
|
||||
*
|
||||
* @param watcher true for synchronous interrupts, false for asynchronous
|
||||
* @return the created interrupt handle
|
||||
*/
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher, int32_t* status);
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status);
|
||||
|
||||
/**
|
||||
* Frees an interrupt.
|
||||
*
|
||||
* @param interruptHandle the interrupt handle
|
||||
* @return the param passed to the interrupt, or nullptr if one
|
||||
* wasn't passed.
|
||||
*/
|
||||
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
|
||||
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle);
|
||||
|
||||
/**
|
||||
* In synchronous mode, waits for the defined interrupt to occur.
|
||||
@@ -52,25 +47,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
double timeout, HAL_Bool ignorePrevious,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Enables interrupts to occur on this input.
|
||||
*
|
||||
* Interrupts are disabled when the RequestInterrupt call is made. This gives
|
||||
* time to do the setup of the other options before starting to field
|
||||
* interrupts.
|
||||
*
|
||||
* @param interruptHandle the interrupt handle
|
||||
*/
|
||||
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle, int32_t* status);
|
||||
|
||||
/**
|
||||
* Disables interrupts without without deallocating structures.
|
||||
*
|
||||
* @param interruptHandle the interrupt handle
|
||||
*/
|
||||
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Returns the timestamp for the rising interrupt that occurred most recently.
|
||||
*
|
||||
@@ -110,34 +86,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
HAL_AnalogTriggerType analogTriggerType,
|
||||
int32_t* status);
|
||||
|
||||
/**
|
||||
* Attaches an asynchronous interrupt handler to the interrupt.
|
||||
*
|
||||
* This interrupt gets called directly on the FPGA interrupt thread, so will
|
||||
* block other interrupts while running.
|
||||
*
|
||||
* @param interruptHandle the interrupt handle
|
||||
* @param handler the handler function for the interrupt to call
|
||||
* @param param a parameter to be passed to the handler
|
||||
*/
|
||||
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status);
|
||||
|
||||
/**
|
||||
* Attaches an asynchronous interrupt handler to the interrupt.
|
||||
*
|
||||
* This interrupt gets called on a thread specific to the interrupt, so will not
|
||||
* block other interrupts.
|
||||
*
|
||||
* @param interruptHandle the interrupt handle
|
||||
* @param handler the handler function for the interrupt to call
|
||||
* @param param a parameter to be passed to the handler
|
||||
*/
|
||||
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status);
|
||||
|
||||
/**
|
||||
* Sets the edges to trigger the interrupt on.
|
||||
*
|
||||
|
||||
@@ -42,16 +42,12 @@ struct Interrupt {
|
||||
HAL_Handle portHandle;
|
||||
uint8_t index;
|
||||
HAL_AnalogTriggerType trigType;
|
||||
bool watcher;
|
||||
int64_t risingTimestamp;
|
||||
int64_t fallingTimestamp;
|
||||
bool previousState;
|
||||
bool fireOnUp;
|
||||
bool fireOnDown;
|
||||
int32_t callbackId;
|
||||
|
||||
void* callbackParam;
|
||||
HAL_InterruptHandlerFunction callbackFunction;
|
||||
};
|
||||
|
||||
struct SynchronousWaitData {
|
||||
@@ -83,8 +79,7 @@ void InitializeInterrupts() {
|
||||
} // namespace hal::init
|
||||
|
||||
extern "C" {
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
|
||||
int32_t* status) {
|
||||
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
|
||||
hal::init::CheckInit();
|
||||
HAL_InterruptHandle handle = interruptHandles->Allocate();
|
||||
if (handle == HAL_kInvalidHandle) {
|
||||
@@ -100,19 +95,10 @@ HAL_InterruptHandle HAL_InitializeInterrupts(HAL_Bool watcher,
|
||||
anInterrupt->index = getHandleIndex(handle);
|
||||
anInterrupt->callbackId = -1;
|
||||
|
||||
anInterrupt->watcher = watcher;
|
||||
|
||||
return handle;
|
||||
}
|
||||
void* HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
HAL_DisableInterrupts(interruptHandle, status);
|
||||
auto anInterrupt = interruptHandles->Get(interruptHandle);
|
||||
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
|
||||
interruptHandles->Free(interruptHandle);
|
||||
if (anInterrupt == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return anInterrupt->callbackParam;
|
||||
}
|
||||
|
||||
static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
|
||||
@@ -352,12 +338,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
return WaitResult::Timeout;
|
||||
}
|
||||
|
||||
// Check to make sure we are actually an interrupt in synchronous mode
|
||||
if (!interrupt->watcher) {
|
||||
*status = NiFpga_Status_InvalidParameter;
|
||||
return WaitResult::Timeout;
|
||||
}
|
||||
|
||||
if (interrupt->isAnalog) {
|
||||
return WaitForInterruptAnalog(interruptHandle, interrupt.get(), timeout,
|
||||
ignorePrevious);
|
||||
@@ -367,196 +347,6 @@ int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
}
|
||||
}
|
||||
|
||||
static void ProcessInterruptDigitalAsynchronous(const char* name, void* param,
|
||||
const struct HAL_Value* value) {
|
||||
// void* is a HAL handle
|
||||
// convert to uintptr_t first, then to handle
|
||||
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
|
||||
HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
|
||||
auto interrupt = interruptHandles->Get(handle);
|
||||
if (interrupt == nullptr) {
|
||||
return;
|
||||
}
|
||||
// Have a valid interrupt
|
||||
if (value->type != HAL_Type::HAL_BOOLEAN) {
|
||||
return;
|
||||
}
|
||||
bool retVal = value->data.v_boolean;
|
||||
// If no change in interrupt, return;
|
||||
if (retVal == interrupt->previousState) {
|
||||
return;
|
||||
}
|
||||
int32_t mask = 0;
|
||||
if (interrupt->previousState) {
|
||||
interrupt->previousState = retVal;
|
||||
interrupt->fallingTimestamp = hal::GetFPGATime();
|
||||
mask = 1 << (8 + interrupt->index);
|
||||
if (!interrupt->fireOnDown) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
interrupt->previousState = retVal;
|
||||
interrupt->risingTimestamp = hal::GetFPGATime();
|
||||
mask = 1 << (interrupt->index);
|
||||
if (!interrupt->fireOnUp) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// run callback
|
||||
auto callback = interrupt->callbackFunction;
|
||||
if (callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
callback(mask, interrupt->callbackParam);
|
||||
}
|
||||
|
||||
static void ProcessInterruptAnalogAsynchronous(const char* name, void* param,
|
||||
const struct HAL_Value* value) {
|
||||
// void* is a HAL handle
|
||||
// convert to intptr_t first, then to handle
|
||||
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
|
||||
HAL_InterruptHandle handle = static_cast<HAL_InterruptHandle>(handleTmp);
|
||||
auto interrupt = interruptHandles->Get(handle);
|
||||
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) {
|
||||
return;
|
||||
}
|
||||
// If no change in interrupt, return;
|
||||
if (retVal == interrupt->previousState) {
|
||||
return;
|
||||
}
|
||||
int mask = 0;
|
||||
if (interrupt->previousState) {
|
||||
interrupt->previousState = retVal;
|
||||
interrupt->fallingTimestamp = hal::GetFPGATime();
|
||||
if (!interrupt->fireOnDown) {
|
||||
return;
|
||||
}
|
||||
mask = 1 << (8 + interrupt->index);
|
||||
} else {
|
||||
interrupt->previousState = retVal;
|
||||
interrupt->risingTimestamp = hal::GetFPGATime();
|
||||
if (!interrupt->fireOnUp) {
|
||||
return;
|
||||
}
|
||||
mask = 1 << (interrupt->index);
|
||||
}
|
||||
|
||||
// run callback
|
||||
auto callback = interrupt->callbackFunction;
|
||||
if (callback == nullptr) {
|
||||
return;
|
||||
}
|
||||
callback(mask, interrupt->callbackParam);
|
||||
}
|
||||
|
||||
static void EnableInterruptsDigital(HAL_InterruptHandle handle,
|
||||
Interrupt* interrupt) {
|
||||
int32_t status = 0;
|
||||
int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
interrupt->previousState = SimDIOData[digitalIndex].value;
|
||||
|
||||
int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
|
||||
&ProcessInterruptDigitalAsynchronous,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
|
||||
interrupt->callbackId = uid;
|
||||
}
|
||||
|
||||
static void EnableInterruptsAnalog(HAL_InterruptHandle handle,
|
||||
Interrupt* interrupt) {
|
||||
int32_t status = 0;
|
||||
int32_t analogIndex =
|
||||
GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
interrupt->previousState = GetAnalogTriggerValue(
|
||||
interrupt->portHandle, interrupt->trigType, &status);
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
|
||||
&ProcessInterruptAnalogAsynchronous,
|
||||
reinterpret_cast<void*>(static_cast<uintptr_t>(handle)), false);
|
||||
interrupt->callbackId = uid;
|
||||
}
|
||||
|
||||
void HAL_EnableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto interrupt = interruptHandles->Get(interruptHandle);
|
||||
if (interrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// If we have not had a callback set, error out
|
||||
if (interrupt->callbackFunction == nullptr) {
|
||||
*status = INCOMPATIBLE_STATE;
|
||||
return;
|
||||
}
|
||||
|
||||
// EnableInterrupts has already been called
|
||||
if (interrupt->callbackId >= 0) {
|
||||
// We can double enable safely.
|
||||
return;
|
||||
}
|
||||
|
||||
if (interrupt->isAnalog) {
|
||||
EnableInterruptsAnalog(interruptHandle, interrupt.get());
|
||||
} else {
|
||||
EnableInterruptsDigital(interruptHandle, interrupt.get());
|
||||
}
|
||||
}
|
||||
void HAL_DisableInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto interrupt = interruptHandles->Get(interruptHandle);
|
||||
if (interrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to disable if we are already disabled
|
||||
if (interrupt->callbackId < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (interrupt->isAnalog) {
|
||||
// Do analog
|
||||
int32_t status = 0;
|
||||
int32_t analogIndex =
|
||||
GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
SimAnalogInData[analogIndex].voltage.CancelCallback(interrupt->callbackId);
|
||||
} else {
|
||||
int32_t status = 0;
|
||||
int32_t digitalIndex =
|
||||
GetDigitalInputChannel(interrupt->portHandle, &status);
|
||||
if (status != 0) {
|
||||
return;
|
||||
}
|
||||
SimDIOData[digitalIndex].value.CancelCallback(interrupt->callbackId);
|
||||
}
|
||||
interrupt->callbackId = -1;
|
||||
}
|
||||
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
auto interrupt = interruptHandles->Get(interruptHandle);
|
||||
@@ -602,24 +392,6 @@ void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
|
||||
interrupt->trigType = analogTriggerType;
|
||||
interrupt->portHandle = digitalSourceHandle;
|
||||
}
|
||||
void HAL_AttachInterruptHandler(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
auto interrupt = interruptHandles->Get(interruptHandle);
|
||||
if (interrupt == nullptr) {
|
||||
*status = HAL_HANDLE_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
interrupt->callbackFunction = handler;
|
||||
interrupt->callbackParam = param;
|
||||
}
|
||||
|
||||
void HAL_AttachInterruptHandlerThreaded(HAL_InterruptHandle interruptHandle,
|
||||
HAL_InterruptHandlerFunction handler,
|
||||
void* param, int32_t* status) {
|
||||
HAL_AttachInterruptHandler(interruptHandle, handler, param, status);
|
||||
}
|
||||
|
||||
void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
|
||||
HAL_Bool risingEdge, HAL_Bool fallingEdge,
|
||||
@@ -636,6 +408,19 @@ void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
|
||||
|
||||
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
|
||||
int32_t* status) {
|
||||
// Requires a fairly large rewrite to get working
|
||||
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"
|
||||
|
||||
Reference in New Issue
Block a user