blob: 7c9a80f4d973ee2949530a790c9b009a24ae1681 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
Brian Silverman1a675112016-02-20 20:42:49 -05002/* Copyright (c) FIRST 2008-2016. All Rights Reserved. */
Brian Silverman26e4e522015-12-17 01:56:40 -05003/* Open Source Software - may be modified and shared by FRC teams. The code */
Brian Silverman1a675112016-02-20 20:42:49 -05004/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
Brian Silverman26e4e522015-12-17 01:56:40 -05006/*----------------------------------------------------------------------------*/
7
8#include "InterruptableSensorBase.h"
9#include "Utility.h"
10#include "WPIErrors.h"
11
12std::unique_ptr<Resource> InterruptableSensorBase::m_interrupts =
13 std::make_unique<Resource>(interrupt_kNumSystems);
14
15InterruptableSensorBase::InterruptableSensorBase() {
16}
17
18/**
19* Request one of the 8 interrupts asynchronously on this digital input.
20* Request interrupts in asynchronous mode where the user's interrupt handler
21* will be
22* called when the interrupt fires. Users that want control over the thread
23* priority
24* should use the synchronous method with their own spawned thread.
25* The default is interrupt on rising edges only.
26*/
27void InterruptableSensorBase::RequestInterrupts(
28 InterruptHandlerFunction handler, void *param) {
29 if (StatusIsFatal()) return;
30 uint32_t index = m_interrupts->Allocate("Async Interrupt");
31 if (index == std::numeric_limits<uint32_t>::max()) {
32 CloneError(*m_interrupts);
33 return;
34 }
35 m_interruptIndex = index;
36
37 // Creates a manager too
38 AllocateInterrupts(false);
39
40 int32_t status = 0;
41 requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(),
42 GetAnalogTriggerForRouting(), &status);
43 SetUpSourceEdge(true, false);
44 attachInterruptHandler(m_interrupt, handler, param, &status);
45 wpi_setErrorWithContext(status, getHALErrorMessage(status));
46}
47
48/**
49* Request one of the 8 interrupts synchronously on this digital input.
50* Request interrupts in synchronous mode where the user program will have to
51* explicitly
52* wait for the interrupt to occur using WaitForInterrupt.
53* The default is interrupt on rising edges only.
54*/
55void InterruptableSensorBase::RequestInterrupts() {
56 if (StatusIsFatal()) return;
57 uint32_t index = m_interrupts->Allocate("Sync Interrupt");
58 if (index == std::numeric_limits<uint32_t>::max()) {
59 CloneError(*m_interrupts);
60 return;
61 }
62 m_interruptIndex = index;
63
64 AllocateInterrupts(true);
65
66 int32_t status = 0;
67 requestInterrupts(m_interrupt, GetModuleForRouting(), GetChannelForRouting(),
68 GetAnalogTriggerForRouting(), &status);
69 wpi_setErrorWithContext(status, getHALErrorMessage(status));
70 SetUpSourceEdge(true, false);
71}
72
73void InterruptableSensorBase::AllocateInterrupts(bool watcher) {
74 wpi_assert(m_interrupt == nullptr);
75 // Expects the calling leaf class to allocate an interrupt index.
76 int32_t status = 0;
77 m_interrupt = initializeInterrupts(m_interruptIndex, watcher, &status);
78 wpi_setErrorWithContext(status, getHALErrorMessage(status));
79}
80
81/**
82 * Cancel interrupts on this device.
83 * This deallocates all the chipobject structures and disables any interrupts.
84 */
85void InterruptableSensorBase::CancelInterrupts() {
86 if (StatusIsFatal()) return;
87 wpi_assert(m_interrupt != nullptr);
88 int32_t status = 0;
89 cleanInterrupts(m_interrupt, &status);
90 wpi_setErrorWithContext(status, getHALErrorMessage(status));
91 m_interrupt = nullptr;
92 m_interrupts->Free(m_interruptIndex);
93}
94
95/**
96 * In synchronous mode, wait for the defined interrupt to occur. You should
97 * <b>NOT</b> attempt to read the
98 * sensor from another thread while waiting for an interrupt. This is not
99 * threadsafe, and can cause
100 * memory corruption
101 * @param timeout Timeout in seconds
102 * @param ignorePrevious If true, ignore interrupts that happened before
103 * WaitForInterrupt was called.
104 * @return What interrupts fired
105 */
106InterruptableSensorBase::WaitResult InterruptableSensorBase::WaitForInterrupt(
107 float timeout, bool ignorePrevious) {
108 if (StatusIsFatal()) return InterruptableSensorBase::kTimeout;
109 wpi_assert(m_interrupt != nullptr);
110 int32_t status = 0;
111 uint32_t result;
112
113 result = waitForInterrupt(m_interrupt, timeout, ignorePrevious, &status);
114 wpi_setErrorWithContext(status, getHALErrorMessage(status));
115
116 return static_cast<WaitResult>(result);
117}
118
119/**
120 * Enable interrupts to occur on this input.
121 * Interrupts are disabled when the RequestInterrupt call is made. This gives
122 * time to do the
123 * setup of the other options before starting to field interrupts.
124 */
125void InterruptableSensorBase::EnableInterrupts() {
126 if (StatusIsFatal()) return;
127 wpi_assert(m_interrupt != nullptr);
128 int32_t status = 0;
129 enableInterrupts(m_interrupt, &status);
130 wpi_setErrorWithContext(status, getHALErrorMessage(status));
131}
132
133/**
134 * Disable Interrupts without without deallocating structures.
135 */
136void InterruptableSensorBase::DisableInterrupts() {
137 if (StatusIsFatal()) return;
138 wpi_assert(m_interrupt != nullptr);
139 int32_t status = 0;
140 disableInterrupts(m_interrupt, &status);
141 wpi_setErrorWithContext(status, getHALErrorMessage(status));
142}
143
144/**
145 * Return the timestamp for the rising interrupt that occurred most recently.
146 * This is in the same time domain as GetClock().
147 * The rising-edge interrupt should be enabled with
148 * {@link #DigitalInput.SetUpSourceEdge}
149 * @return Timestamp in seconds since boot.
150 */
151double InterruptableSensorBase::ReadRisingTimestamp() {
152 if (StatusIsFatal()) return 0.0;
153 wpi_assert(m_interrupt != nullptr);
154 int32_t status = 0;
155 double timestamp = readRisingTimestamp(m_interrupt, &status);
156 wpi_setErrorWithContext(status, getHALErrorMessage(status));
157 return timestamp;
158}
159
160/**
161 * Return the timestamp for the falling interrupt that occurred most recently.
162 * This is in the same time domain as GetClock().
163 * The falling-edge interrupt should be enabled with
164 * {@link #DigitalInput.SetUpSourceEdge}
165 * @return Timestamp in seconds since boot.
166*/
167double InterruptableSensorBase::ReadFallingTimestamp() {
168 if (StatusIsFatal()) return 0.0;
169 wpi_assert(m_interrupt != nullptr);
170 int32_t status = 0;
171 double timestamp = readFallingTimestamp(m_interrupt, &status);
172 wpi_setErrorWithContext(status, getHALErrorMessage(status));
173 return timestamp;
174}
175
176/**
177 * Set which edge to trigger interrupts on
178 *
179 * @param risingEdge
180 * true to interrupt on rising edge
181 * @param fallingEdge
182 * true to interrupt on falling edge
183 */
184void InterruptableSensorBase::SetUpSourceEdge(bool risingEdge,
185 bool fallingEdge) {
186 if (StatusIsFatal()) return;
187 if (m_interrupt == nullptr) {
188 wpi_setWPIErrorWithContext(
189 NullParameter,
190 "You must call RequestInterrupts before SetUpSourceEdge");
191 return;
192 }
193 if (m_interrupt != nullptr) {
194 int32_t status = 0;
195 setInterruptUpSourceEdge(m_interrupt, risingEdge, fallingEdge, &status);
196 wpi_setErrorWithContext(status, getHALErrorMessage(status));
197 }
198}