blob: 4becafcd76cb5174c355376ceb0847274eae51f4 [file] [log] [blame]
Parker Schuhd3b7a8872018-02-19 16:42:27 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008-2017. All Rights Reserved. */
3/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "frc971/wpilib/ahal/InterruptableSensorBase.h"
9
Austin Schuhf6b94632019-02-02 22:11:27 -080010#include "hal/HAL.h"
Parker Schuhd3b7a8872018-02-19 16:42:27 -080011#include "frc971/wpilib/ahal/Utility.h"
12#include "frc971/wpilib/ahal/WPIErrors.h"
13
14using namespace frc;
15
Austin Schuhf6b94632019-02-02 22:11:27 -080016namespace {
Parker Schuhd3b7a8872018-02-19 16:42:27 -080017
Austin Schuhf6b94632019-02-02 22:11:27 -080018// Converts a freestanding lower half to a 64 bit FPGA timestamp
19//
20// Note: This is making the assumption that the timestamp being converted is
21// always in the past. If you call this with a future timestamp, it probably
22// will make it in the past. If you wait over 70 minutes between capturing the
23// bottom 32 bits of the timestamp and expanding it, you will be off by
24// multiples of 1<<32 microseconds.
25//
26// @return The current time in microseconds according to the FPGA (since FPGA
27// reset) as a 64 bit number.
28uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status) {
29 // Capture the current FPGA time. This will give us the upper half of the
30 // clock.
31 uint64_t fpga_time = HAL_GetFPGATime(status);
32 if (*status != 0) return 0;
Parker Schuhd3b7a8872018-02-19 16:42:27 -080033
Austin Schuhf6b94632019-02-02 22:11:27 -080034 // Now, we need to detect the case where the lower bits rolled over after we
35 // sampled. In that case, the upper bits will be 1 bigger than they should
36 // be.
Parker Schuhd3b7a8872018-02-19 16:42:27 -080037
Austin Schuhf6b94632019-02-02 22:11:27 -080038 // Break it into lower and upper portions.
39 uint32_t lower = fpga_time & ((uint64_t)0xffffffff);
40 uint64_t upper = (fpga_time >> 32) & 0xffffffff;
41
42 // The time was sampled *before* the current time, so roll it back.
43 if (lower < unexpanded_lower) {
44 --upper;
45 }
46
47 return (upper << 32) + static_cast<uint64_t>(unexpanded_lower);
Parker Schuhd3b7a8872018-02-19 16:42:27 -080048}
49
Austin Schuhf6b94632019-02-02 22:11:27 -080050} // namespace
51
52InterruptableSensorBase::InterruptableSensorBase() {}
53
Parker Schuhd3b7a8872018-02-19 16:42:27 -080054void InterruptableSensorBase::RequestInterrupts() {
55 if (StatusIsFatal()) return;
56
57 wpi_assert(m_interrupt == HAL_kInvalidHandle);
58 AllocateInterrupts(true);
59 if (StatusIsFatal()) return; // if allocate failed, out of interrupts
60
61 int32_t status = 0;
62 HAL_RequestInterrupts(
63 m_interrupt, GetPortHandleForRouting(),
64 static_cast<HAL_AnalogTriggerType>(GetAnalogTriggerTypeForRouting()),
65 &status);
66 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
67 SetUpSourceEdge(true, false);
68}
69
70void InterruptableSensorBase::AllocateInterrupts(bool watcher) {
71 wpi_assert(m_interrupt == HAL_kInvalidHandle);
72 // Expects the calling leaf class to allocate an interrupt index.
73 int32_t status = 0;
74 m_interrupt = HAL_InitializeInterrupts(watcher, &status);
75 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
76}
77
Parker Schuhd3b7a8872018-02-19 16:42:27 -080078void InterruptableSensorBase::CancelInterrupts() {
79 if (StatusIsFatal()) return;
80 wpi_assert(m_interrupt != HAL_kInvalidHandle);
81 int32_t status = 0;
82 HAL_CleanInterrupts(m_interrupt, &status);
83 // ignore status, as an invalid handle just needs to be ignored.
84 m_interrupt = HAL_kInvalidHandle;
85}
86
Parker Schuhd3b7a8872018-02-19 16:42:27 -080087InterruptableSensorBase::WaitResult InterruptableSensorBase::WaitForInterrupt(
88 double timeout, bool ignorePrevious) {
89 if (StatusIsFatal()) return InterruptableSensorBase::kTimeout;
90 wpi_assert(m_interrupt != HAL_kInvalidHandle);
91 int32_t status = 0;
92 int result;
93
94 result = HAL_WaitForInterrupt(m_interrupt, timeout, ignorePrevious, &status);
95 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
96
97 // Rising edge result is the interrupt bit set in the byte 0xFF
98 // Falling edge result is the interrupt bit set in the byte 0xFF00
99 // Set any bit set to be true for that edge, and AND the 2 results
100 // together to match the existing enum for all interrupts
101 int32_t rising = (result & 0xFF) ? 0x1 : 0x0;
102 int32_t falling = ((result & 0xFF00) ? 0x0100 : 0x0);
103 return static_cast<WaitResult>(falling | rising);
104}
105
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800106void InterruptableSensorBase::EnableInterrupts() {
107 if (StatusIsFatal()) return;
108 wpi_assert(m_interrupt != HAL_kInvalidHandle);
109 int32_t status = 0;
110 HAL_EnableInterrupts(m_interrupt, &status);
111 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
112}
113
Austin Schuhf6b94632019-02-02 22:11:27 -0800114hal::fpga_clock::time_point InterruptableSensorBase::ReadRisingTimestamp() {
115 if (StatusIsFatal()) return hal::fpga_clock::min_time;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800116 wpi_assert(m_interrupt != HAL_kInvalidHandle);
117 int32_t status = 0;
Austin Schuhf6b94632019-02-02 22:11:27 -0800118 uint64_t timestamp = HAL_ReadInterruptRisingTimestamp(m_interrupt, &status);
119 timestamp = HAL_ExpandFPGATime(timestamp, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800120 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
Austin Schuhf6b94632019-02-02 22:11:27 -0800121 return hal::fpga_clock::time_point(hal::fpga_clock::duration(timestamp));
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800122}
123
Austin Schuhf6b94632019-02-02 22:11:27 -0800124hal::fpga_clock::time_point InterruptableSensorBase::ReadFallingTimestamp() {
125 if (StatusIsFatal()) return hal::fpga_clock::min_time;
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800126 wpi_assert(m_interrupt != HAL_kInvalidHandle);
127 int32_t status = 0;
Austin Schuhf6b94632019-02-02 22:11:27 -0800128 uint64_t timestamp = HAL_ReadInterruptFallingTimestamp(m_interrupt, &status);
129 timestamp = HAL_ExpandFPGATime(timestamp, &status);
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800130 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
Austin Schuhf6b94632019-02-02 22:11:27 -0800131 return hal::fpga_clock::time_point(hal::fpga_clock::duration(timestamp));
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800132}
133
Parker Schuhd3b7a8872018-02-19 16:42:27 -0800134void InterruptableSensorBase::SetUpSourceEdge(bool risingEdge,
135 bool fallingEdge) {
136 if (StatusIsFatal()) return;
137 if (m_interrupt == HAL_kInvalidHandle) {
138 wpi_setWPIErrorWithContext(
139 NullParameter,
140 "You must call RequestInterrupts before SetUpSourceEdge");
141 return;
142 }
143 if (m_interrupt != HAL_kInvalidHandle) {
144 int32_t status = 0;
145 HAL_SetInterruptUpSourceEdge(m_interrupt, risingEdge, fallingEdge, &status);
146 wpi_setErrorWithContext(status, HAL_GetErrorMessage(status));
147 }
148}