blob: 64c4a1090dd9f572547e1f39dc9087ac68add1b8 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2016-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/HAL.h"
9
Austin Schuh1e69f942020-11-14 15:06:14 -080010#include <vector>
11
Brian Silverman8fce7482020-01-05 13:18:21 -080012#include <wpi/mutex.h>
13#include <wpi/raw_ostream.h>
Austin Schuh1e69f942020-11-14 15:06:14 -080014#include <wpi/spinlock.h>
15
16#ifdef _WIN32
17#include <Windows.h>
18#pragma comment(lib, "Winmm.lib")
19#endif // _WIN32
Brian Silverman8fce7482020-01-05 13:18:21 -080020
21#include "ErrorsInternal.h"
22#include "HALInitializer.h"
23#include "MockHooksInternal.h"
24#include "hal/DriverStation.h"
25#include "hal/Errors.h"
26#include "hal/Extensions.h"
27#include "hal/handles/HandlesInternal.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080028#include "hal/simulation/DriverStationData.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080029#include "mockdata/RoboRioDataInternal.h"
30
31using namespace hal;
32
Austin Schuh1e69f942020-11-14 15:06:14 -080033static HAL_RuntimeType runtimeType{HAL_Mock};
34static wpi::spinlock gOnShutdownMutex;
35static std::vector<std::pair<void*, void (*)(void*)>> gOnShutdown;
36
Brian Silverman8fce7482020-01-05 13:18:21 -080037namespace hal {
38namespace init {
39void InitializeHAL() {
40 InitializeAccelerometerData();
41 InitializeAddressableLEDData();
42 InitializeAnalogGyroData();
43 InitializeAnalogInData();
44 InitializeAnalogOutData();
45 InitializeAnalogTriggerData();
46 InitializeCanData();
47 InitializeCANAPI();
48 InitializeDigitalPWMData();
49 InitializeDutyCycleData();
50 InitializeDIOData();
51 InitializeDriverStationData();
52 InitializeEncoderData();
53 InitializeI2CData();
54 InitializePCMData();
55 InitializePDPData();
56 InitializePWMData();
57 InitializeRelayData();
58 InitializeRoboRioData();
59 InitializeSimDeviceData();
60 InitializeSPIAccelerometerData();
61 InitializeSPIData();
62 InitializeAccelerometer();
63 InitializeAddressableLED();
64 InitializeAnalogAccumulator();
65 InitializeAnalogGyro();
66 InitializeAnalogInput();
67 InitializeAnalogInternal();
68 InitializeAnalogOutput();
Austin Schuh1e69f942020-11-14 15:06:14 -080069 InitializeAnalogTrigger();
Brian Silverman8fce7482020-01-05 13:18:21 -080070 InitializeCAN();
71 InitializeCompressor();
72 InitializeConstants();
73 InitializeCounter();
74 InitializeDigitalInternal();
75 InitializeDIO();
76 InitializeDutyCycle();
77 InitializeDriverStation();
78 InitializeEncoder();
79 InitializeExtensions();
80 InitializeI2C();
81 InitializeInterrupts();
82 InitializeMain();
83 InitializeMockHooks();
84 InitializeNotifier();
85 InitializePDP();
86 InitializePorts();
87 InitializePower();
88 InitializePWM();
89 InitializeRelay();
90 InitializeSerialPort();
91 InitializeSimDevice();
92 InitializeSolenoid();
93 InitializeSPI();
94 InitializeThreads();
95}
96} // namespace init
97} // namespace hal
98
99extern "C" {
100
101HAL_PortHandle HAL_GetPort(int32_t channel) {
102 // Dont allow a number that wouldn't fit in a uint8_t
103 if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
104 return createPortHandle(channel, 1);
105}
106
107HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
108 // Dont allow a number that wouldn't fit in a uint8_t
109 if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
110 if (module < 0 || module >= 255) return HAL_kInvalidHandle;
111 return createPortHandle(channel, module);
112}
113
114const char* HAL_GetErrorMessage(int32_t code) {
115 switch (code) {
116 case 0:
117 return "";
118 case CTR_RxTimeout:
119 return CTR_RxTimeout_MESSAGE;
120 case CTR_TxTimeout:
121 return CTR_TxTimeout_MESSAGE;
122 case CTR_InvalidParamValue:
123 return CTR_InvalidParamValue_MESSAGE;
124 case CTR_UnexpectedArbId:
125 return CTR_UnexpectedArbId_MESSAGE;
126 case CTR_TxFailed:
127 return CTR_TxFailed_MESSAGE;
128 case CTR_SigNotUpdated:
129 return CTR_SigNotUpdated_MESSAGE;
130 case NiFpga_Status_FifoTimeout:
131 return NiFpga_Status_FifoTimeout_MESSAGE;
132 case NiFpga_Status_TransferAborted:
133 return NiFpga_Status_TransferAborted_MESSAGE;
134 case NiFpga_Status_MemoryFull:
135 return NiFpga_Status_MemoryFull_MESSAGE;
136 case NiFpga_Status_SoftwareFault:
137 return NiFpga_Status_SoftwareFault_MESSAGE;
138 case NiFpga_Status_InvalidParameter:
139 return NiFpga_Status_InvalidParameter_MESSAGE;
140 case NiFpga_Status_ResourceNotFound:
141 return NiFpga_Status_ResourceNotFound_MESSAGE;
142 case NiFpga_Status_ResourceNotInitialized:
143 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
144 case NiFpga_Status_HardwareFault:
145 return NiFpga_Status_HardwareFault_MESSAGE;
146 case NiFpga_Status_IrqTimeout:
147 return NiFpga_Status_IrqTimeout_MESSAGE;
148 case SAMPLE_RATE_TOO_HIGH:
149 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
150 case VOLTAGE_OUT_OF_RANGE:
151 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
152 case LOOP_TIMING_ERROR:
153 return LOOP_TIMING_ERROR_MESSAGE;
154 case SPI_WRITE_NO_MOSI:
155 return SPI_WRITE_NO_MOSI_MESSAGE;
156 case SPI_READ_NO_MISO:
157 return SPI_READ_NO_MISO_MESSAGE;
158 case SPI_READ_NO_DATA:
159 return SPI_READ_NO_DATA_MESSAGE;
160 case INCOMPATIBLE_STATE:
161 return INCOMPATIBLE_STATE_MESSAGE;
162 case NO_AVAILABLE_RESOURCES:
163 return NO_AVAILABLE_RESOURCES_MESSAGE;
164 case RESOURCE_IS_ALLOCATED:
165 return RESOURCE_IS_ALLOCATED_MESSAGE;
166 case RESOURCE_OUT_OF_RANGE:
167 return RESOURCE_OUT_OF_RANGE_MESSAGE;
168 case HAL_INVALID_ACCUMULATOR_CHANNEL:
169 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
170 case HAL_HANDLE_ERROR:
171 return HAL_HANDLE_ERROR_MESSAGE;
172 case NULL_PARAMETER:
173 return NULL_PARAMETER_MESSAGE;
174 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
175 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
176 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
177 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
178 case PARAMETER_OUT_OF_RANGE:
179 return PARAMETER_OUT_OF_RANGE_MESSAGE;
180 case HAL_COUNTER_NOT_SUPPORTED:
181 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
182 case HAL_ERR_CANSessionMux_InvalidBuffer:
183 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
184 case HAL_ERR_CANSessionMux_MessageNotFound:
185 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
186 case HAL_WARN_CANSessionMux_NoToken:
187 return WARN_CANSessionMux_NoToken_MESSAGE;
188 case HAL_ERR_CANSessionMux_NotAllowed:
189 return ERR_CANSessionMux_NotAllowed_MESSAGE;
190 case HAL_ERR_CANSessionMux_NotInitialized:
191 return ERR_CANSessionMux_NotInitialized_MESSAGE;
192 case VI_ERROR_SYSTEM_ERROR:
193 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
194 case VI_ERROR_INV_OBJECT:
195 return VI_ERROR_INV_OBJECT_MESSAGE;
196 case VI_ERROR_RSRC_LOCKED:
197 return VI_ERROR_RSRC_LOCKED_MESSAGE;
198 case VI_ERROR_RSRC_NFOUND:
199 return VI_ERROR_RSRC_NFOUND_MESSAGE;
200 case VI_ERROR_INV_RSRC_NAME:
201 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
202 case VI_ERROR_QUEUE_OVERFLOW:
203 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
204 case VI_ERROR_IO:
205 return VI_ERROR_IO_MESSAGE;
206 case VI_ERROR_ASRL_PARITY:
207 return VI_ERROR_ASRL_PARITY_MESSAGE;
208 case VI_ERROR_ASRL_FRAMING:
209 return VI_ERROR_ASRL_FRAMING_MESSAGE;
210 case VI_ERROR_ASRL_OVERRUN:
211 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
212 case VI_ERROR_RSRC_BUSY:
213 return VI_ERROR_RSRC_BUSY_MESSAGE;
214 case VI_ERROR_INV_PARAMETER:
215 return VI_ERROR_INV_PARAMETER_MESSAGE;
216 case HAL_PWM_SCALE_ERROR:
217 return HAL_PWM_SCALE_ERROR_MESSAGE;
218 case HAL_CAN_TIMEOUT:
219 return HAL_CAN_TIMEOUT_MESSAGE;
220 case HAL_SIM_NOT_SUPPORTED:
221 return HAL_SIM_NOT_SUPPORTED_MESSAGE;
222 case HAL_CAN_BUFFER_OVERRUN:
223 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
224 case HAL_LED_CHANNEL_ERROR:
225 return HAL_LED_CHANNEL_ERROR_MESSAGE;
226 default:
227 return "Unknown error status";
228 }
229}
230
Austin Schuh1e69f942020-11-14 15:06:14 -0800231HAL_RuntimeType HAL_GetRuntimeType(void) { return runtimeType; }
232
233void HALSIM_SetRuntimeType(HAL_RuntimeType type) { runtimeType = type; }
Brian Silverman8fce7482020-01-05 13:18:21 -0800234
235int32_t HAL_GetFPGAVersion(int32_t* status) {
236 return 2018; // Automatically script this at some point
237}
238
239int64_t HAL_GetFPGARevision(int32_t* status) {
240 return 0; // TODO: Find a better number to return;
241}
242
243uint64_t HAL_GetFPGATime(int32_t* status) { return hal::GetFPGATime(); }
244
245uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status) {
246 // Capture the current FPGA time. This will give us the upper half of the
247 // clock.
248 uint64_t fpga_time = HAL_GetFPGATime(status);
249 if (*status != 0) return 0;
250
251 // Now, we need to detect the case where the lower bits rolled over after we
252 // sampled. In that case, the upper bits will be 1 bigger than they should
253 // be.
254
255 // Break it into lower and upper portions.
256 uint32_t lower = fpga_time & 0xffffffffull;
257 uint64_t upper = (fpga_time >> 32) & 0xffffffff;
258
259 // The time was sampled *before* the current time, so roll it back.
260 if (lower < unexpanded_lower) {
261 --upper;
262 }
263
264 return (upper << 32) + static_cast<uint64_t>(unexpanded_lower);
265}
266
267HAL_Bool HAL_GetFPGAButton(int32_t* status) {
268 return SimRoboRioData[0].fpgaButton;
269}
270
271HAL_Bool HAL_GetSystemActive(int32_t* status) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800272 return HALSIM_GetDriverStationEnabled();
Brian Silverman8fce7482020-01-05 13:18:21 -0800273}
274
275HAL_Bool HAL_GetBrownedOut(int32_t* status) {
276 return false; // Figure out if we need to detect a brownout condition
277}
278
279HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
280 static std::atomic_bool initialized{false};
281 static wpi::mutex initializeMutex;
282 // Initial check, as if it's true initialization has finished
283 if (initialized) return true;
284
285 std::scoped_lock lock(initializeMutex);
286 // Second check in case another thread was waiting
287 if (initialized) return true;
288
289 hal::init::InitializeHAL();
290
291 hal::init::HAL_IsInitialized.store(true);
292
Brian Silverman8fce7482020-01-05 13:18:21 -0800293 hal::RestartTiming();
294 HAL_InitializeDriverStation();
295
296 initialized = true;
Austin Schuh1e69f942020-11-14 15:06:14 -0800297
298// Set Timer Precision to 1ms on Windows
299#ifdef _WIN32
300 TIMECAPS tc;
301 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
302 UINT target = min(1, tc.wPeriodMin);
303 timeBeginPeriod(target);
304 std::atexit([]() {
305 TIMECAPS tc;
306 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
307 UINT target = min(1, tc.wPeriodMin);
308 timeEndPeriod(target);
309 }
310 });
311 }
312#endif // _WIN32
313
314 wpi::outs().SetUnbuffered();
315 if (HAL_LoadExtensions() < 0) return false;
316
Brian Silverman8fce7482020-01-05 13:18:21 -0800317 return true; // Add initialization if we need to at a later point
318}
319
Austin Schuh1e69f942020-11-14 15:06:14 -0800320void HAL_Shutdown(void) {
321 std::vector<std::pair<void*, void (*)(void*)>> funcs;
322 {
323 std::scoped_lock lock(gOnShutdownMutex);
324 funcs.swap(gOnShutdown);
325 }
326 for (auto&& func : funcs) {
327 func.second(func.first);
328 }
329}
330
331void HAL_OnShutdown(void* param, void (*func)(void*)) {
332 std::scoped_lock lock(gOnShutdownMutex);
333 gOnShutdown.emplace_back(param, func);
334}
335
Brian Silverman8fce7482020-01-05 13:18:21 -0800336int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
337 const char* feature) {
338 return 0; // Do nothing for now
339}
340
341} // extern "C"