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