Austin Schuh | 812d0d1 | 2021-11-04 20:16:48 -0700 | [diff] [blame^] | 1 | // Copyright (c) FIRST and other WPILib contributors. |
| 2 | // Open Source Software; you can modify and/or share it under the terms of |
| 3 | // the WPILib BSD license file in the root directory of this project. |
| 4 | |
| 5 | #include "frc/SynchronousInterrupt.h" |
| 6 | |
| 7 | #include <type_traits> |
| 8 | |
| 9 | #include <hal/Interrupts.h> |
| 10 | #include <wpi/NullDeleter.h> |
| 11 | |
| 12 | #include "frc/DigitalSource.h" |
| 13 | #include "frc/Errors.h" |
| 14 | |
| 15 | using namespace frc; |
| 16 | |
| 17 | SynchronousInterrupt::SynchronousInterrupt(DigitalSource& source) |
| 18 | : m_source{&source, wpi::NullDeleter<DigitalSource>()} { |
| 19 | InitSynchronousInterrupt(); |
| 20 | } |
| 21 | SynchronousInterrupt::SynchronousInterrupt(DigitalSource* source) |
| 22 | : m_source{source, wpi::NullDeleter<DigitalSource>()} { |
| 23 | if (m_source == nullptr) { |
| 24 | FRC_CheckErrorStatus(frc::err::NullParameter, "{}", "Source is null"); |
| 25 | } else { |
| 26 | InitSynchronousInterrupt(); |
| 27 | } |
| 28 | } |
| 29 | SynchronousInterrupt::SynchronousInterrupt( |
| 30 | std::shared_ptr<DigitalSource> source) |
| 31 | : m_source{std::move(source)} { |
| 32 | if (m_source == nullptr) { |
| 33 | FRC_CheckErrorStatus(frc::err::NullParameter, "{}", "Source is null"); |
| 34 | } else { |
| 35 | InitSynchronousInterrupt(); |
| 36 | } |
| 37 | } |
| 38 | |
| 39 | void SynchronousInterrupt::InitSynchronousInterrupt() { |
| 40 | int32_t status = 0; |
| 41 | m_handle = HAL_InitializeInterrupts(&status); |
| 42 | FRC_CheckErrorStatus(status, "{}", "Interrupt failed to initialize"); |
| 43 | HAL_RequestInterrupts(m_handle, m_source->GetPortHandleForRouting(), |
| 44 | static_cast<HAL_AnalogTriggerType>( |
| 45 | m_source->GetAnalogTriggerTypeForRouting()), |
| 46 | &status); |
| 47 | FRC_CheckErrorStatus(status, "{}", "Interrupt request failed"); |
| 48 | HAL_SetInterruptUpSourceEdge(m_handle, true, false, &status); |
| 49 | FRC_CheckErrorStatus(status, "{}", "Interrupt setting up source edge failed"); |
| 50 | } |
| 51 | |
| 52 | SynchronousInterrupt::~SynchronousInterrupt() { |
| 53 | HAL_CleanInterrupts(m_handle); |
| 54 | } |
| 55 | |
| 56 | inline SynchronousInterrupt::WaitResult operator|( |
| 57 | SynchronousInterrupt::WaitResult lhs, |
| 58 | SynchronousInterrupt::WaitResult rhs) { |
| 59 | using T = std::underlying_type_t<SynchronousInterrupt::WaitResult>; |
| 60 | return static_cast<SynchronousInterrupt::WaitResult>(static_cast<T>(lhs) | |
| 61 | static_cast<T>(rhs)); |
| 62 | } |
| 63 | |
| 64 | SynchronousInterrupt::WaitResult SynchronousInterrupt::WaitForInterrupt( |
| 65 | units::second_t timeout, bool ignorePrevious) { |
| 66 | int32_t status = 0; |
| 67 | auto result = |
| 68 | HAL_WaitForInterrupt(m_handle, timeout.value(), ignorePrevious, &status); |
| 69 | |
| 70 | auto rising = |
| 71 | ((result & 0xFF) != 0) ? WaitResult::kRisingEdge : WaitResult::kTimeout; |
| 72 | auto falling = ((result & 0xFF00) != 0) ? WaitResult::kFallingEdge |
| 73 | : WaitResult::kTimeout; |
| 74 | |
| 75 | return rising | falling; |
| 76 | } |
| 77 | |
| 78 | void SynchronousInterrupt::SetInterruptEdges(bool risingEdge, |
| 79 | bool fallingEdge) { |
| 80 | int32_t status = 0; |
| 81 | HAL_SetInterruptUpSourceEdge(m_handle, risingEdge, fallingEdge, &status); |
| 82 | FRC_CheckErrorStatus(status, "{}", "Interrupt setting edges failed"); |
| 83 | } |
| 84 | |
| 85 | void SynchronousInterrupt::WakeupWaitingInterrupt() { |
| 86 | int32_t status = 0; |
| 87 | HAL_ReleaseWaitingInterrupt(m_handle, &status); |
| 88 | FRC_CheckErrorStatus(status, "{}", "Interrupt wakeup failed"); |
| 89 | } |
| 90 | |
| 91 | units::second_t SynchronousInterrupt::GetRisingTimestamp() { |
| 92 | int32_t status = 0; |
| 93 | auto ts = HAL_ReadInterruptRisingTimestamp(m_handle, &status); |
| 94 | FRC_CheckErrorStatus(status, "{}", "Interrupt rising timestamp failed"); |
| 95 | units::microsecond_t ms{static_cast<double>(ts)}; |
| 96 | return ms; |
| 97 | } |
| 98 | |
| 99 | units::second_t SynchronousInterrupt::GetFallingTimestamp() { |
| 100 | int32_t status = 0; |
| 101 | auto ts = HAL_ReadInterruptFallingTimestamp(m_handle, &status); |
| 102 | FRC_CheckErrorStatus(status, "{}", "Interrupt falling timestamp failed"); |
| 103 | units::microsecond_t ms{static_cast<double>(ts)}; |
| 104 | return ms; |
| 105 | } |