2020-12-26 14:12:05 -08:00
|
|
|
// 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.
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/Interrupts.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
|
2018-04-29 23:33:19 -07:00
|
|
|
#include <wpi/condition_variable.h>
|
2017-11-13 09:51:48 -08:00
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
#include "AnalogInternal.h"
|
|
|
|
|
#include "DigitalInternal.h"
|
|
|
|
|
#include "ErrorsInternal.h"
|
2018-05-13 22:02:47 -07:00
|
|
|
#include "HALInitializer.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
#include "MockHooksInternal.h"
|
|
|
|
|
#include "PortsInternal.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/AnalogTrigger.h"
|
|
|
|
|
#include "hal/Errors.h"
|
2019-09-23 23:28:49 -07:00
|
|
|
#include "hal/Value.h"
|
2018-07-20 00:03:45 -07:00
|
|
|
#include "hal/handles/HandlesInternal.h"
|
|
|
|
|
#include "hal/handles/LimitedHandleResource.h"
|
|
|
|
|
#include "hal/handles/UnlimitedHandleResource.h"
|
|
|
|
|
#include "mockdata/AnalogInDataInternal.h"
|
|
|
|
|
#include "mockdata/DIODataInternal.h"
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2019-05-31 13:43:32 -07:00
|
|
|
#ifdef _WIN32
|
|
|
|
|
#pragma warning(disable : 4996 4018 6297 26451 4334)
|
|
|
|
|
#endif
|
|
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
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;
|
2018-11-15 21:22:03 -08:00
|
|
|
int64_t risingTimestamp;
|
|
|
|
|
int64_t fallingTimestamp;
|
2024-07-16 20:26:35 -04:00
|
|
|
bool currentState;
|
2017-08-18 21:35:53 -07:00
|
|
|
bool fireOnUp;
|
|
|
|
|
bool fireOnDown;
|
|
|
|
|
int32_t callbackId;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct SynchronousWaitData {
|
2019-05-31 13:43:32 -07:00
|
|
|
HAL_InterruptHandle interruptHandle{HAL_kInvalidHandle};
|
2017-11-13 09:51:48 -08:00
|
|
|
wpi::condition_variable waitCond;
|
2019-05-31 13:43:32 -07:00
|
|
|
HAL_Bool waitPredicate{false};
|
2017-08-18 21:35:53 -07:00
|
|
|
};
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
|
|
static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
|
2017-12-10 19:38:53 -08:00
|
|
|
HAL_HandleEnum::Interrupt>* interruptHandles;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2021-06-10 11:13:09 -07:00
|
|
|
using SynchronousWaitDataHandle = HAL_Handle;
|
2017-08-18 21:35:53 -07:00
|
|
|
static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
|
2017-12-10 19:38:53 -08:00
|
|
|
HAL_HandleEnum::Vendor>*
|
2017-08-18 21:35:53 -07:00
|
|
|
synchronousInterruptHandles;
|
|
|
|
|
|
2020-12-28 01:19:59 -08:00
|
|
|
namespace hal::init {
|
2017-12-10 19:38:53 -08:00
|
|
|
void InitializeInterrupts() {
|
|
|
|
|
static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
|
|
|
|
|
HAL_HandleEnum::Interrupt>
|
|
|
|
|
iH;
|
|
|
|
|
interruptHandles = &iH;
|
|
|
|
|
static UnlimitedHandleResource<SynchronousWaitDataHandle, SynchronousWaitData,
|
|
|
|
|
HAL_HandleEnum::Vendor>
|
|
|
|
|
siH;
|
|
|
|
|
synchronousInterruptHandles = &siH;
|
|
|
|
|
}
|
2020-12-28 01:19:59 -08:00
|
|
|
} // namespace hal::init
|
2017-12-10 19:38:53 -08:00
|
|
|
|
2017-08-18 21:35:53 -07:00
|
|
|
extern "C" {
|
2021-06-05 11:25:21 -07:00
|
|
|
HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
|
2018-05-13 22:02:47 -07:00
|
|
|
hal::init::CheckInit();
|
2017-12-10 19:38:53 -08:00
|
|
|
HAL_InterruptHandle handle = interruptHandles->Allocate();
|
2017-08-18 21:35:53 -07:00
|
|
|
if (handle == HAL_kInvalidHandle) {
|
|
|
|
|
*status = NO_AVAILABLE_RESOURCES;
|
|
|
|
|
return HAL_kInvalidHandle;
|
|
|
|
|
}
|
2017-12-10 19:38:53 -08:00
|
|
|
auto anInterrupt = interruptHandles->Get(handle);
|
2017-08-18 21:35:53 -07:00
|
|
|
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;
|
|
|
|
|
}
|
2021-06-05 11:25:21 -07:00
|
|
|
void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
|
2017-12-10 19:38:53 -08:00
|
|
|
interruptHandles->Free(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void ProcessInterruptDigitalSynchronous(const char* name, void* param,
|
|
|
|
|
const struct HAL_Value* value) {
|
|
|
|
|
// void* is a SynchronousWaitDataHandle.
|
2017-11-09 14:01:24 -08:00
|
|
|
// convert to uintptr_t first, then to handle
|
|
|
|
|
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
|
2017-08-18 21:35:53 -07:00
|
|
|
SynchronousWaitDataHandle handle =
|
|
|
|
|
static_cast<SynchronousWaitDataHandle>(handleTmp);
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interruptData = synchronousInterruptHandles->Get(handle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (interruptData == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (interrupt == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// Have a valid interrupt
|
2020-12-28 12:58:06 -08:00
|
|
|
if (value->type != HAL_Type::HAL_BOOLEAN) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
bool retVal = value->data.v_boolean;
|
2024-07-16 20:26:35 -04:00
|
|
|
auto previousState = interrupt->currentState;
|
|
|
|
|
interrupt->currentState = retVal;
|
2017-08-18 21:35:53 -07:00
|
|
|
// If no change in interrupt, return;
|
2021-09-11 09:21:02 -07:00
|
|
|
if (retVal == previousState) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// If its a falling change, and we dont fire on falling return
|
2021-09-11 09:21:02 -07:00
|
|
|
if (previousState && !interrupt->fireOnDown) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// If its a rising change, and we dont fire on rising return.
|
2021-09-11 09:21:02 -07:00
|
|
|
if (!previousState && !interrupt->fireOnUp) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
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.
|
2017-11-09 14:01:24 -08:00
|
|
|
// convert to uintptr_t first, then to handle
|
|
|
|
|
uintptr_t handleTmp = reinterpret_cast<uintptr_t>(param);
|
2017-08-18 21:35:53 -07:00
|
|
|
SynchronousWaitDataHandle handle =
|
|
|
|
|
static_cast<SynchronousWaitDataHandle>(handleTmp);
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interruptData = synchronousInterruptHandles->Get(handle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (interruptData == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptData->interruptHandle);
|
2020-12-28 12:58:06 -08:00
|
|
|
if (interrupt == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// Have a valid interrupt
|
2020-12-28 12:58:06 -08:00
|
|
|
if (value->type != HAL_Type::HAL_DOUBLE) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
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();
|
|
|
|
|
}
|
2024-07-16 20:26:35 -04:00
|
|
|
auto previousState = interrupt->currentState;
|
|
|
|
|
interrupt->currentState = retVal;
|
2017-08-18 21:35:53 -07:00
|
|
|
// If no change in interrupt, return;
|
2021-09-11 09:21:02 -07:00
|
|
|
if (retVal == previousState) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// If its a falling change, and we dont fire on falling return
|
2021-09-11 09:21:02 -07:00
|
|
|
if (previousState && !interrupt->fireOnDown) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
// If its a rising change, and we dont fire on rising return.
|
2021-09-11 09:21:02 -07:00
|
|
|
if (!previousState && !interrupt->fireOnUp) {
|
2020-12-28 12:58:06 -08:00
|
|
|
return;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
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<SynchronousWaitData>();
|
|
|
|
|
|
2017-12-10 19:38:53 -08:00
|
|
|
auto dataHandle = synchronousInterruptHandles->Allocate(data);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (dataHandle == HAL_kInvalidHandle) {
|
|
|
|
|
// Error allocating data
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
|
|
|
|
|
2017-12-10 19:38:53 -08:00
|
|
|
// auto data = synchronousInterruptHandles->Get(dataHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
data->waitPredicate = false;
|
|
|
|
|
data->interruptHandle = handle;
|
|
|
|
|
|
|
|
|
|
int32_t status = 0;
|
|
|
|
|
|
|
|
|
|
int32_t digitalIndex = GetDigitalInputChannel(interrupt->portHandle, &status);
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (status != 0) {
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2024-07-16 20:26:35 -04:00
|
|
|
interrupt->currentState = SimDIOData[digitalIndex].value;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
int32_t uid = SimDIOData[digitalIndex].value.RegisterCallback(
|
2017-11-09 14:01:24 -08:00
|
|
|
&ProcessInterruptDigitalSynchronous,
|
|
|
|
|
reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
bool timedOut = false;
|
|
|
|
|
|
2017-11-13 09:51:48 -08:00
|
|
|
wpi::mutex waitMutex;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
auto timeoutTime =
|
|
|
|
|
std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
|
|
|
|
|
|
|
|
|
|
{
|
2019-07-07 19:17:14 -07:00
|
|
|
std::unique_lock lock(waitMutex);
|
2017-08-18 21:35:53 -07:00
|
|
|
while (!data->waitPredicate) {
|
|
|
|
|
if (data->waitCond.wait_until(lock, timeoutTime) ==
|
|
|
|
|
std::cv_status::timeout) {
|
|
|
|
|
timedOut = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cancel our callback
|
2018-09-03 16:08:07 -07:00
|
|
|
SimDIOData[digitalIndex].value.CancelCallback(uid);
|
2019-05-31 13:43:32 -07:00
|
|
|
(void)synchronousInterruptHandles->Free(dataHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
// Check for what to return
|
2020-12-28 12:58:06 -08:00
|
|
|
if (timedOut) {
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
2024-07-16 20:26:35 -04:00
|
|
|
// 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) {
|
2017-08-18 21:35:53 -07:00
|
|
|
// Set our return value and our timestamps
|
2018-11-15 21:22:03 -08:00
|
|
|
interrupt->risingTimestamp = hal::GetFPGATime();
|
2017-08-18 21:35:53 -07:00
|
|
|
return 1 << (interrupt->index);
|
2024-07-16 20:26:35 -04:00
|
|
|
} else {
|
|
|
|
|
interrupt->fallingTimestamp = hal::GetFPGATime();
|
|
|
|
|
return 1 << (8 + interrupt->index);
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int64_t WaitForInterruptAnalog(HAL_InterruptHandle handle,
|
|
|
|
|
Interrupt* interrupt, double timeout,
|
|
|
|
|
bool ignorePrevious) {
|
|
|
|
|
auto data = std::make_shared<SynchronousWaitData>();
|
|
|
|
|
|
2017-12-10 19:38:53 -08:00
|
|
|
auto dataHandle = synchronousInterruptHandles->Allocate(data);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (dataHandle == HAL_kInvalidHandle) {
|
|
|
|
|
// Error allocating data
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
data->waitPredicate = false;
|
|
|
|
|
data->interruptHandle = handle;
|
|
|
|
|
|
|
|
|
|
int32_t status = 0;
|
2024-07-16 20:26:35 -04:00
|
|
|
interrupt->currentState = GetAnalogTriggerValue(interrupt->portHandle,
|
|
|
|
|
interrupt->trigType, &status);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (status != 0) {
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
int32_t analogIndex =
|
|
|
|
|
GetAnalogTriggerInputIndex(interrupt->portHandle, &status);
|
|
|
|
|
|
2020-12-28 12:58:06 -08:00
|
|
|
if (status != 0) {
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
2017-08-18 21:35:53 -07:00
|
|
|
|
2018-09-03 16:08:07 -07:00
|
|
|
int32_t uid = SimAnalogInData[analogIndex].voltage.RegisterCallback(
|
2017-11-09 14:01:24 -08:00
|
|
|
&ProcessInterruptAnalogSynchronous,
|
|
|
|
|
reinterpret_cast<void*>(static_cast<uintptr_t>(dataHandle)), false);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
bool timedOut = false;
|
|
|
|
|
|
2017-11-13 09:51:48 -08:00
|
|
|
wpi::mutex waitMutex;
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
auto timeoutTime =
|
|
|
|
|
std::chrono::steady_clock::now() + std::chrono::duration<double>(timeout);
|
|
|
|
|
|
|
|
|
|
{
|
2019-07-07 19:17:14 -07:00
|
|
|
std::unique_lock lock(waitMutex);
|
2017-08-18 21:35:53 -07:00
|
|
|
while (!data->waitPredicate) {
|
|
|
|
|
if (data->waitCond.wait_until(lock, timeoutTime) ==
|
|
|
|
|
std::cv_status::timeout) {
|
|
|
|
|
timedOut = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Cancel our callback
|
2018-09-03 16:08:07 -07:00
|
|
|
SimAnalogInData[analogIndex].voltage.CancelCallback(uid);
|
2019-05-31 13:43:32 -07:00
|
|
|
(void)synchronousInterruptHandles->Free(dataHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
|
|
|
|
|
// Check for what to return
|
2020-12-28 12:58:06 -08:00
|
|
|
if (timedOut) {
|
|
|
|
|
return WaitResult::Timeout;
|
|
|
|
|
}
|
2024-07-16 20:26:35 -04:00
|
|
|
// 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) {
|
2017-08-18 21:35:53 -07:00
|
|
|
// Set our return value and our timestamps
|
2018-11-15 21:22:03 -08:00
|
|
|
interrupt->risingTimestamp = hal::GetFPGATime();
|
2017-08-18 21:35:53 -07:00
|
|
|
return 1 << (interrupt->index);
|
2024-07-16 20:26:35 -04:00
|
|
|
} else {
|
|
|
|
|
interrupt->fallingTimestamp = hal::GetFPGATime();
|
|
|
|
|
return 1 << (8 + interrupt->index);
|
2017-08-18 21:35:53 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
|
|
|
|
|
double timeout, HAL_Bool ignorePrevious,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-13 17:25:54 -07:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-15 21:22:03 -08:00
|
|
|
int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (interrupt == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return interrupt->risingTimestamp;
|
|
|
|
|
}
|
2018-11-15 21:22:03 -08:00
|
|
|
int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
|
|
|
|
|
int32_t* status) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
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) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
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) {
|
2017-12-10 19:38:53 -08:00
|
|
|
auto interrupt = interruptHandles->Get(interruptHandle);
|
2017-08-18 21:35:53 -07:00
|
|
|
if (interrupt == nullptr) {
|
|
|
|
|
*status = HAL_HANDLE_ERROR;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
interrupt->fireOnDown = fallingEdge;
|
|
|
|
|
interrupt->fireOnUp = risingEdge;
|
|
|
|
|
}
|
2020-02-18 20:41:42 -08:00
|
|
|
|
|
|
|
|
void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
|
|
|
|
|
int32_t* status) {
|
2021-06-05 11:25:21 -07:00
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
});
|
2020-02-18 20:41:42 -08:00
|
|
|
}
|
2017-11-16 01:05:20 -08:00
|
|
|
} // extern "C"
|