blob: 75a09fbb17abfbeef0779b770e1331227db467d4 [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/AddressableLED.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <fmt/format.h>
8
Brian Silverman8fce7482020-01-05 13:18:21 -08009#include "DigitalInternal.h"
10#include "HALInitializer.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070011#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080012#include "PortsInternal.h"
13#include "hal/Errors.h"
14#include "hal/handles/HandlesInternal.h"
15#include "hal/handles/LimitedHandleResource.h"
16#include "mockdata/AddressableLEDDataInternal.h"
17
18using namespace hal;
19
20namespace {
21struct AddressableLED {
22 uint8_t index;
23};
24} // namespace
25
26static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
27 kNumAddressableLEDs,
28 HAL_HandleEnum::AddressableLED>* ledHandles;
29
Austin Schuh812d0d12021-11-04 20:16:48 -070030namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080031void InitializeAddressableLED() {
32 static LimitedHandleResource<HAL_AddressableLEDHandle, AddressableLED,
33 kNumAddressableLEDs,
34 HAL_HandleEnum::AddressableLED>
35 dcH;
36 ledHandles = &dcH;
37}
Austin Schuh812d0d12021-11-04 20:16:48 -070038} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -080039
40extern "C" {
41HAL_AddressableLEDHandle HAL_InitializeAddressableLED(
42 HAL_DigitalHandle outputPort, int32_t* status) {
43 hal::init::CheckInit();
44
45 auto digitalPort =
46 hal::digitalChannelHandles->Get(outputPort, hal::HAL_HandleEnum::PWM);
47
48 if (!digitalPort) {
49 // If DIO was passed, channel error, else generic error
50 if (getHandleType(outputPort) == hal::HAL_HandleEnum::DIO) {
51 *status = HAL_LED_CHANNEL_ERROR;
52 } else {
53 *status = HAL_HANDLE_ERROR;
54 }
55 return HAL_kInvalidHandle;
56 }
57
58 if (digitalPort->channel >= kNumPWMHeaders) {
59 *status = HAL_LED_CHANNEL_ERROR;
60 return HAL_kInvalidHandle;
61 }
62
63 HAL_AddressableLEDHandle handle = ledHandles->Allocate();
64 if (handle == HAL_kInvalidHandle) {
65 *status = NO_AVAILABLE_RESOURCES;
66 return HAL_kInvalidHandle;
67 }
68
69 auto led = ledHandles->Get(handle);
70 if (!led) { // would only occur on thread issue
71 *status = HAL_HANDLE_ERROR;
72 return HAL_kInvalidHandle;
73 }
74
75 int16_t index = getHandleIndex(handle);
76 SimAddressableLEDData[index].outputPort = digitalPort->channel;
77 SimAddressableLEDData[index].length = 1;
78 SimAddressableLEDData[index].running = false;
79 SimAddressableLEDData[index].initialized = true;
80 led->index = index;
81 return handle;
82}
83
84void HAL_FreeAddressableLED(HAL_AddressableLEDHandle handle) {
85 auto led = ledHandles->Get(handle);
86 ledHandles->Free(handle);
Austin Schuh812d0d12021-11-04 20:16:48 -070087 if (!led) {
88 return;
89 }
Brian Silverman8fce7482020-01-05 13:18:21 -080090 SimAddressableLEDData[led->index].running = false;
91 SimAddressableLEDData[led->index].initialized = false;
92}
93
94void HAL_SetAddressableLEDOutputPort(HAL_AddressableLEDHandle handle,
95 HAL_DigitalHandle outputPort,
96 int32_t* status) {
97 auto led = ledHandles->Get(handle);
98 if (!led) {
99 *status = HAL_HANDLE_ERROR;
100 return;
101 }
102 if (auto port = digitalChannelHandles->Get(outputPort, HAL_HandleEnum::PWM)) {
103 SimAddressableLEDData[led->index].outputPort = port->channel;
104 } else {
105 SimAddressableLEDData[led->index].outputPort = -1;
106 }
107}
108
109void HAL_SetAddressableLEDLength(HAL_AddressableLEDHandle handle,
110 int32_t length, int32_t* status) {
111 auto led = ledHandles->Get(handle);
112 if (!led) {
113 *status = HAL_HANDLE_ERROR;
114 return;
115 }
Austin Schuh812d0d12021-11-04 20:16:48 -0700116 if (length > HAL_kAddressableLEDMaxLength || length < 0) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800117 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700118 hal::SetLastError(
119 status,
120 fmt::format(
121 "LED length must be less than or equal to {}. {} was requested",
122 HAL_kAddressableLEDMaxLength, length));
Brian Silverman8fce7482020-01-05 13:18:21 -0800123 return;
124 }
125 SimAddressableLEDData[led->index].length = length;
126}
127
128void HAL_WriteAddressableLEDData(HAL_AddressableLEDHandle handle,
129 const struct HAL_AddressableLEDData* data,
130 int32_t length, int32_t* status) {
131 auto led = ledHandles->Get(handle);
132 if (!led) {
133 *status = HAL_HANDLE_ERROR;
134 return;
135 }
136 if (length > SimAddressableLEDData[led->index].length) {
137 *status = PARAMETER_OUT_OF_RANGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700138 hal::SetLastError(
139 status,
140 fmt::format(
141 "Data length must be less than or equal to {}. {} was requested",
142 SimAddressableLEDData[led->index].length, length));
Brian Silverman8fce7482020-01-05 13:18:21 -0800143 return;
144 }
145 SimAddressableLEDData[led->index].SetData(data, length);
146}
147
148void HAL_SetAddressableLEDBitTiming(HAL_AddressableLEDHandle handle,
149 int32_t lowTime0NanoSeconds,
150 int32_t highTime0NanoSeconds,
151 int32_t lowTime1NanoSeconds,
152 int32_t highTime1NanoSeconds,
153 int32_t* status) {}
154
155void HAL_SetAddressableLEDSyncTime(HAL_AddressableLEDHandle handle,
156 int32_t syncTimeMicroSeconds,
157 int32_t* status) {}
158
159void HAL_StartAddressableLEDOutput(HAL_AddressableLEDHandle handle,
160 int32_t* status) {
161 auto led = ledHandles->Get(handle);
162 if (!led) {
163 *status = HAL_HANDLE_ERROR;
164 return;
165 }
166 SimAddressableLEDData[led->index].running = true;
167}
168
169void HAL_StopAddressableLEDOutput(HAL_AddressableLEDHandle handle,
170 int32_t* status) {
171 auto led = ledHandles->Get(handle);
172 if (!led) {
173 *status = HAL_HANDLE_ERROR;
174 return;
175 }
176 SimAddressableLEDData[led->index].running = false;
177}
178} // extern "C"