blob: e40c6f4550c7127d91ab478c5eee4a4e5493e49b [file] [log] [blame]
Austin Schuh812d0d12021-11-04 20:16:48 -07001// 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.
Brian Silverman8fce7482020-01-05 13:18:21 -08004
5#include "hal/Interrupts.h"
6
7#include <memory>
8
9#include <wpi/SafeThread.h>
10
11#include "DigitalInternal.h"
12#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080013#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080014#include "PortsInternal.h"
15#include "hal/ChipObject.h"
16#include "hal/Errors.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080017#include "hal/HALBase.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080018#include "hal/handles/HandlesInternal.h"
19#include "hal/handles/LimitedHandleResource.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080020#include "hal/roborio/InterruptManager.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080021
22using namespace hal;
23
24namespace {
Brian Silverman8fce7482020-01-05 13:18:21 -080025
26struct Interrupt {
27 std::unique_ptr<tInterrupt> anInterrupt;
James Kuszmaulcf324122023-01-14 14:07:17 -080028 InterruptManager& manager = InterruptManager::GetInstance();
29 NiFpga_IrqContext irqContext = nullptr;
30 uint32_t mask;
Brian Silverman8fce7482020-01-05 13:18:21 -080031};
32
33} // namespace
34
Brian Silverman8fce7482020-01-05 13:18:21 -080035static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
36 HAL_HandleEnum::Interrupt>* interruptHandles;
37
Austin Schuh812d0d12021-11-04 20:16:48 -070038namespace hal::init {
Austin Schuh1e69f942020-11-14 15:06:14 -080039void InitializeInterrupts() {
Brian Silverman8fce7482020-01-05 13:18:21 -080040 static LimitedHandleResource<HAL_InterruptHandle, Interrupt, kNumInterrupts,
41 HAL_HandleEnum::Interrupt>
42 iH;
43 interruptHandles = &iH;
44}
Austin Schuh812d0d12021-11-04 20:16:48 -070045} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080046
47extern "C" {
48
Austin Schuh812d0d12021-11-04 20:16:48 -070049HAL_InterruptHandle HAL_InitializeInterrupts(int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -080050 hal::init::CheckInit();
51 HAL_InterruptHandle handle = interruptHandles->Allocate();
52 if (handle == HAL_kInvalidHandle) {
53 *status = NO_AVAILABLE_RESOURCES;
54 return HAL_kInvalidHandle;
55 }
56 auto anInterrupt = interruptHandles->Get(handle);
57 uint32_t interruptIndex = static_cast<uint32_t>(getHandleIndex(handle));
58 // Expects the calling leaf class to allocate an interrupt index.
59 anInterrupt->anInterrupt.reset(tInterrupt::create(interruptIndex, status));
60 anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
James Kuszmaulcf324122023-01-14 14:07:17 -080061 anInterrupt->irqContext = anInterrupt->manager.GetContext();
62 anInterrupt->mask = (1u << interruptIndex) | (1u << (interruptIndex + 8u));
Brian Silverman8fce7482020-01-05 13:18:21 -080063 return handle;
64}
65
Austin Schuh812d0d12021-11-04 20:16:48 -070066void HAL_CleanInterrupts(HAL_InterruptHandle interruptHandle) {
Brian Silverman8fce7482020-01-05 13:18:21 -080067 auto anInterrupt = interruptHandles->Get(interruptHandle);
68 interruptHandles->Free(interruptHandle);
69 if (anInterrupt == nullptr) {
Austin Schuh812d0d12021-11-04 20:16:48 -070070 return;
Brian Silverman8fce7482020-01-05 13:18:21 -080071 }
James Kuszmaulcf324122023-01-14 14:07:17 -080072 if (anInterrupt->irqContext) {
73 anInterrupt->manager.ReleaseContext(anInterrupt->irqContext);
74 }
Brian Silverman8fce7482020-01-05 13:18:21 -080075}
76
77int64_t HAL_WaitForInterrupt(HAL_InterruptHandle interruptHandle,
78 double timeout, HAL_Bool ignorePrevious,
79 int32_t* status) {
80 uint32_t result;
81 auto anInterrupt = interruptHandles->Get(interruptHandle);
82 if (anInterrupt == nullptr) {
83 *status = HAL_HANDLE_ERROR;
84 return 0;
85 }
86
James Kuszmaulcf324122023-01-14 14:07:17 -080087 result = anInterrupt->manager.WaitForInterrupt(
88 anInterrupt->irqContext, anInterrupt->mask, ignorePrevious,
89 static_cast<uint32_t>(timeout * 1e3), status);
90
91 // Don't report a timeout as an error - the return code is enough to tell
92 // that a timeout happened.
93 if (*status == -NiFpga_Status_IrqTimeout) {
94 *status = NiFpga_Status_Success;
95 }
96
97 return result;
98}
99
100int64_t HAL_WaitForMultipleInterrupts(HAL_InterruptHandle interruptHandle,
101 int64_t mask, double timeout,
102 HAL_Bool ignorePrevious,
103 int32_t* status) {
104 uint32_t result;
105 auto anInterrupt = interruptHandles->Get(interruptHandle);
106 if (anInterrupt == nullptr) {
107 *status = HAL_HANDLE_ERROR;
108 return 0;
109 }
110
111 result = anInterrupt->manager.WaitForInterrupt(
112 anInterrupt->irqContext, mask, ignorePrevious,
113 static_cast<uint32_t>(timeout * 1e3), status);
Brian Silverman8fce7482020-01-05 13:18:21 -0800114
115 // Don't report a timeout as an error - the return code is enough to tell
116 // that a timeout happened.
117 if (*status == -NiFpga_Status_IrqTimeout) {
118 *status = NiFpga_Status_Success;
119 }
120
121 return result;
122}
123
Brian Silverman8fce7482020-01-05 13:18:21 -0800124int64_t HAL_ReadInterruptRisingTimestamp(HAL_InterruptHandle interruptHandle,
125 int32_t* status) {
126 auto anInterrupt = interruptHandles->Get(interruptHandle);
127 if (anInterrupt == nullptr) {
128 *status = HAL_HANDLE_ERROR;
129 return 0;
130 }
131 uint32_t timestamp = anInterrupt->anInterrupt->readRisingTimeStamp(status);
132 return timestamp;
133}
134
135int64_t HAL_ReadInterruptFallingTimestamp(HAL_InterruptHandle interruptHandle,
136 int32_t* status) {
137 auto anInterrupt = interruptHandles->Get(interruptHandle);
138 if (anInterrupt == nullptr) {
139 *status = HAL_HANDLE_ERROR;
140 return 0;
141 }
142 uint32_t timestamp = anInterrupt->anInterrupt->readFallingTimeStamp(status);
143 return timestamp;
144}
145
146void HAL_RequestInterrupts(HAL_InterruptHandle interruptHandle,
147 HAL_Handle digitalSourceHandle,
148 HAL_AnalogTriggerType analogTriggerType,
149 int32_t* status) {
150 auto anInterrupt = interruptHandles->Get(interruptHandle);
151 if (anInterrupt == nullptr) {
152 *status = HAL_HANDLE_ERROR;
153 return;
154 }
155 anInterrupt->anInterrupt->writeConfig_WaitForAck(false, status);
156 bool routingAnalogTrigger = false;
157 uint8_t routingChannel = 0;
158 uint8_t routingModule = 0;
159 bool success =
160 remapDigitalSource(digitalSourceHandle, analogTriggerType, routingChannel,
161 routingModule, routingAnalogTrigger);
162 if (!success) {
163 *status = HAL_HANDLE_ERROR;
164 return;
165 }
166 anInterrupt->anInterrupt->writeConfig_Source_AnalogTrigger(
167 routingAnalogTrigger, status);
168 anInterrupt->anInterrupt->writeConfig_Source_Channel(routingChannel, status);
169 anInterrupt->anInterrupt->writeConfig_Source_Module(routingModule, status);
170}
171
Brian Silverman8fce7482020-01-05 13:18:21 -0800172void HAL_SetInterruptUpSourceEdge(HAL_InterruptHandle interruptHandle,
173 HAL_Bool risingEdge, HAL_Bool fallingEdge,
174 int32_t* status) {
175 auto anInterrupt = interruptHandles->Get(interruptHandle);
176 if (anInterrupt == nullptr) {
177 *status = HAL_HANDLE_ERROR;
178 return;
179 }
180 anInterrupt->anInterrupt->writeConfig_RisingEdge(risingEdge, status);
181 anInterrupt->anInterrupt->writeConfig_FallingEdge(fallingEdge, status);
182}
183
Austin Schuh1e69f942020-11-14 15:06:14 -0800184void HAL_ReleaseWaitingInterrupt(HAL_InterruptHandle interruptHandle,
185 int32_t* status) {
186 auto anInterrupt = interruptHandles->Get(interruptHandle);
187 if (anInterrupt == nullptr) {
188 *status = HAL_HANDLE_ERROR;
189 return;
190 }
191
192 uint32_t interruptIndex =
193 static_cast<uint32_t>(getHandleIndex(interruptHandle));
194
195 hal::ReleaseFPGAInterrupt(interruptIndex);
196 hal::ReleaseFPGAInterrupt(interruptIndex + 8);
197}
198
Brian Silverman8fce7482020-01-05 13:18:21 -0800199} // extern "C"