blob: 64b64570b047a9a6a5d2d76e04a6a087739a8ea4 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
2/* Copyright (c) 2019 FIRST. 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 "hal/AddressableLED.h"
9
10#include <cstring>
11
12#include <FRC_FPGA_ChipObject/fpgainterfacecapi/NiFpga_HMB.h>
13
14#include "ConstantsInternal.h"
15#include "DigitalInternal.h"
16#include "HALInitializer.h"
17#include "PortsInternal.h"
18#include "hal/ChipObject.h"
19#include "hal/handles/HandlesInternal.h"
20#include "hal/handles/LimitedHandleResource.h"
21
22using namespace hal;
23
24namespace {
25struct AddressableLED {
26 std::unique_ptr<tLED> led;
27 void* ledBuffer;
28 size_t ledBufferSize;
29 int32_t stringLength = 1;
30};
31} // namespace
32
33static LimitedHandleResource<
34 HAL_AddressableLEDHandle, AddressableLED, kNumAddressableLEDs,
35 HAL_HandleEnum::AddressableLED>* addressableLEDHandles;
36
37namespace hal {
38namespace init {
39void InitializeAddressableLED() {
40 static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
41 kNumAddressableLEDs,
42 HAL_HandleEnum::AddressableLED>
43 alH;
44 addressableLEDHandles = &alH;
45}
46} // namespace init
47} // namespace hal
48
49extern "C" {
50
51HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
52 HAL_DigitalHandle outputPort, int32_t* status) {
53 hal::init::CheckInit();
54
55 auto digitalPort =
56 hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
57
58 if (!digitalPort) {
59 // If DIO was passed, channel error, else generic error
60 if (getHandleType(outputPort) == hal::HAL_HandleEnum::DIO) {
61 *status = HAL_LED_CHANNEL_ERROR;
62 } else {
63 *status = HAL_HANDLE_ERROR;
64 }
65 return HAL_kInvalidHandle;
66 }
67
68 if (digitalPort->channel >= kNumPWMHeaders) {
69 *status = HAL_LED_CHANNEL_ERROR;
70 return HAL_kInvalidHandle;
71 }
72
73 auto handle = addressableLEDHandles->Allocate();
74
75 if (handle == HAL_kInvalidHandle) {
76 *status = NO_AVAILABLE_RESOURCES;
77 return HAL_kInvalidHandle;
78 }
79
80 auto led = addressableLEDHandles->Get(handle);
81
82 if (!led) {
83 *status = HAL_HANDLE_ERROR;
84 return HAL_kInvalidHandle;
85 }
86
87 led->led.reset(tLED::create(status));
88
89 if (*status != 0) {
90 addressableLEDHandles->Free(handle);
91 return HAL_kInvalidHandle;
92 }
93
94 led->led->writeOutputSelect(digitalPort->channel, status);
95
96 if (*status != 0) {
97 addressableLEDHandles->Free(handle);
98 return HAL_kInvalidHandle;
99 }
100
101 led->ledBuffer = nullptr;
102 led->ledBufferSize = 0;
103
104 uint32_t session = led->led->getSystemInterface()->getHandle();
105
106 *status = NiFpga_OpenHostMemoryBuffer(session, "HMB_0_LED", &led->ledBuffer,
107 &led->ledBufferSize);
108
109 if (*status != 0) {
110 addressableLEDHandles->Free(handle);
111 return HAL_kInvalidHandle;
112 }
113
114 return handle;
115}
116
117void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
118 addressableLEDHandles->Free(handle);
119}
120
121void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
122 HAL_DigitalHandle outputPort,
123 int32_t* status) {
124 auto digitalPort =
125 hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
126
127 if (!digitalPort) {
128 *status = HAL_HANDLE_ERROR;
129 return;
130 }
131
132 auto led = addressableLEDHandles->Get(handle);
133 if (!led) {
134 *status = HAL_HANDLE_ERROR;
135 return;
136 }
137
138 led->led->writeOutputSelect(digitalPort->channel, status);
139}
140
141void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
142 int32_t length, int32_t* status) {
143 auto led = addressableLEDHandles->Get(handle);
144 if (!led) {
145 *status = HAL_HANDLE_ERROR;
146 return;
147 }
148
149 if (length > HAL_kAddressableLEDMaxLength) {
150 *status = PARAMETER_OUT_OF_RANGE;
151 return;
152 }
153
154 led->led->strobeReset(status);
155
156 while (led->led->readPixelWriteIndex(status) != 0) {
157 }
158
159 if (*status != 0) {
160 return;
161 }
162
163 led->led->writeStringLength(length, status);
164
165 led->stringLength = length;
166}
167
168static_assert(sizeof(HAL_AddressableLEDData) == sizeof(uint32_t),
169 "LED Data must be 32 bit");
170
171void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
172 const struct HAL_AddressableLEDData* data,
173 int32_t length, int32_t* status) {
174 auto led = addressableLEDHandles->Get(handle);
175 if (!led) {
176 *status = HAL_HANDLE_ERROR;
177 return;
178 }
179
180 if (length > led->stringLength) {
181 *status = PARAMETER_OUT_OF_RANGE;
182 return;
183 }
184
185 std::memcpy(led->ledBuffer, data, length * sizeof(HAL_AddressableLEDData));
186
187 asm("dmb");
188
189 led->led->strobeLoad(status);
190}
191
192void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
193 int32_t lowTime0NanoSeconds,
194 int32_t highTime0NanoSeconds,
195 int32_t lowTime1NanoSeconds,
196 int32_t highTime1NanoSeconds,
197 int32_t* status) {
198 auto led = addressableLEDHandles->Get(handle);
199 if (!led) {
200 *status = HAL_HANDLE_ERROR;
201 return;
202 }
203
204 led->led->writeLowBitTickTiming(1, highTime0NanoSeconds / 25, status);
205 led->led->writeLowBitTickTiming(0, lowTime0NanoSeconds / 25, status);
206 led->led->writeHighBitTickTiming(1, highTime1NanoSeconds / 25, status);
207 led->led->writeHighBitTickTiming(0, lowTime1NanoSeconds / 25, status);
208}
209
210void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
211 int32_t syncTimeMicroSeconds,
212 int32_t* status) {
213 auto led = addressableLEDHandles->Get(handle);
214 if (!led) {
215 *status = HAL_HANDLE_ERROR;
216 return;
217 }
218
219 led->led->writeSyncTiming(syncTimeMicroSeconds, status);
220}
221
222void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
223 int32_t* status) {
224 auto led = addressableLEDHandles->Get(handle);
225 if (!led) {
226 *status = HAL_HANDLE_ERROR;
227 return;
228 }
229
230 led->led->strobeStart(status);
231}
232
233void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
234 int32_t* status) {
235 auto led = addressableLEDHandles->Get(handle);
236 if (!led) {
237 *status = HAL_HANDLE_ERROR;
238 return;
239 }
240
241 led->led->strobeAbort(status);
242}
243} // extern "C"