// 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 "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"); } SynchronousInterrupt::~SynchronousInterrupt() { HAL_CleanInterrupts(m_handle); } 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.to(), 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; }