blob: ce8b6dde5ff361d73256a7882f638c8b839832f9 [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/HAL.h"
6
Austin Schuh812d0d12021-11-04 20:16:48 -07007#include <cstdio>
Austin Schuh1e69f942020-11-14 15:06:14 -08008#include <vector>
9
Brian Silverman8fce7482020-01-05 13:18:21 -080010#include <wpi/mutex.h>
Austin Schuh1e69f942020-11-14 15:06:14 -080011#include <wpi/spinlock.h>
12
13#ifdef _WIN32
14#include <Windows.h>
15#pragma comment(lib, "Winmm.lib")
16#endif // _WIN32
Brian Silverman8fce7482020-01-05 13:18:21 -080017
18#include "ErrorsInternal.h"
19#include "HALInitializer.h"
20#include "MockHooksInternal.h"
21#include "hal/DriverStation.h"
22#include "hal/Errors.h"
23#include "hal/Extensions.h"
24#include "hal/handles/HandlesInternal.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080025#include "hal/simulation/DriverStationData.h"
Austin Schuh812d0d12021-11-04 20:16:48 -070026#include "hal/simulation/SimCallbackRegistry.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080027#include "mockdata/RoboRioDataInternal.h"
28
29using namespace hal;
30
Austin Schuh812d0d12021-11-04 20:16:48 -070031namespace {
32class SimPeriodicCallbackRegistry : public impl::SimCallbackRegistryBase {
33 public:
34 int32_t Register(HALSIM_SimPeriodicCallback callback, void* param) {
35 std::scoped_lock lock(m_mutex);
36 return DoRegister(reinterpret_cast<RawFunctor>(callback), param);
37 }
38
39 void operator()() const {
40#ifdef _MSC_VER // work around VS2019 16.4.0 bug
41 std::scoped_lock<wpi::recursive_spinlock> lock(m_mutex);
42#else
43 std::scoped_lock lock(m_mutex);
44#endif
45 if (m_callbacks) {
46 for (auto&& cb : *m_callbacks) {
47 reinterpret_cast<HALSIM_SimPeriodicCallback>(cb.callback)(cb.param);
48 }
49 }
50 }
51};
52} // namespace
53
54static HAL_RuntimeType runtimeType{HAL_Runtime_Simulation};
Austin Schuh1e69f942020-11-14 15:06:14 -080055static wpi::spinlock gOnShutdownMutex;
56static std::vector<std::pair<void*, void (*)(void*)>> gOnShutdown;
Austin Schuh812d0d12021-11-04 20:16:48 -070057static SimPeriodicCallbackRegistry gSimPeriodicBefore;
58static SimPeriodicCallbackRegistry gSimPeriodicAfter;
Austin Schuh1e69f942020-11-14 15:06:14 -080059
James Kuszmaulcf324122023-01-14 14:07:17 -080060namespace hal {
61void InitializeDriverStation();
62} // namespace hal
63
Austin Schuh812d0d12021-11-04 20:16:48 -070064namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080065void InitializeHAL() {
66 InitializeAccelerometerData();
67 InitializeAddressableLEDData();
68 InitializeAnalogGyroData();
69 InitializeAnalogInData();
70 InitializeAnalogOutData();
71 InitializeAnalogTriggerData();
72 InitializeCanData();
73 InitializeCANAPI();
74 InitializeDigitalPWMData();
75 InitializeDutyCycleData();
76 InitializeDIOData();
77 InitializeDriverStationData();
78 InitializeEncoderData();
79 InitializeI2CData();
Austin Schuh812d0d12021-11-04 20:16:48 -070080 InitializeCTREPCMData();
81 InitializeREVPHData();
82 InitializePowerDistributionData();
Brian Silverman8fce7482020-01-05 13:18:21 -080083 InitializePWMData();
84 InitializeRelayData();
85 InitializeRoboRioData();
86 InitializeSimDeviceData();
87 InitializeSPIAccelerometerData();
88 InitializeSPIData();
89 InitializeAccelerometer();
90 InitializeAddressableLED();
91 InitializeAnalogAccumulator();
92 InitializeAnalogGyro();
93 InitializeAnalogInput();
94 InitializeAnalogInternal();
95 InitializeAnalogOutput();
Austin Schuh1e69f942020-11-14 15:06:14 -080096 InitializeAnalogTrigger();
Brian Silverman8fce7482020-01-05 13:18:21 -080097 InitializeCAN();
Brian Silverman8fce7482020-01-05 13:18:21 -080098 InitializeConstants();
99 InitializeCounter();
100 InitializeDigitalInternal();
101 InitializeDIO();
102 InitializeDutyCycle();
103 InitializeDriverStation();
104 InitializeEncoder();
105 InitializeExtensions();
106 InitializeI2C();
107 InitializeInterrupts();
108 InitializeMain();
109 InitializeMockHooks();
110 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -0700111 InitializePowerDistribution();
Brian Silverman8fce7482020-01-05 13:18:21 -0800112 InitializePorts();
113 InitializePower();
Austin Schuh812d0d12021-11-04 20:16:48 -0700114 InitializeCTREPCM();
115 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -0800116 InitializePWM();
117 InitializeRelay();
118 InitializeSerialPort();
119 InitializeSimDevice();
Brian Silverman8fce7482020-01-05 13:18:21 -0800120 InitializeSPI();
121 InitializeThreads();
122}
Austin Schuh812d0d12021-11-04 20:16:48 -0700123} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800124
125extern "C" {
126
127HAL_PortHandle HAL_GetPort(int32_t channel) {
128 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700129 if (channel < 0 || channel >= 255) {
130 return HAL_kInvalidHandle;
131 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800132 return createPortHandle(channel, 1);
133}
134
135HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
136 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700137 if (channel < 0 || channel >= 255) {
138 return HAL_kInvalidHandle;
139 }
140 if (module < 0 || module >= 255) {
141 return HAL_kInvalidHandle;
142 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800143 return createPortHandle(channel, module);
144}
145
146const char* HAL_GetErrorMessage(int32_t code) {
147 switch (code) {
148 case 0:
149 return "";
150 case CTR_RxTimeout:
151 return CTR_RxTimeout_MESSAGE;
152 case CTR_TxTimeout:
153 return CTR_TxTimeout_MESSAGE;
154 case CTR_InvalidParamValue:
155 return CTR_InvalidParamValue_MESSAGE;
156 case CTR_UnexpectedArbId:
157 return CTR_UnexpectedArbId_MESSAGE;
158 case CTR_TxFailed:
159 return CTR_TxFailed_MESSAGE;
160 case CTR_SigNotUpdated:
161 return CTR_SigNotUpdated_MESSAGE;
162 case NiFpga_Status_FifoTimeout:
163 return NiFpga_Status_FifoTimeout_MESSAGE;
164 case NiFpga_Status_TransferAborted:
165 return NiFpga_Status_TransferAborted_MESSAGE;
166 case NiFpga_Status_MemoryFull:
167 return NiFpga_Status_MemoryFull_MESSAGE;
168 case NiFpga_Status_SoftwareFault:
169 return NiFpga_Status_SoftwareFault_MESSAGE;
170 case NiFpga_Status_InvalidParameter:
171 return NiFpga_Status_InvalidParameter_MESSAGE;
172 case NiFpga_Status_ResourceNotFound:
173 return NiFpga_Status_ResourceNotFound_MESSAGE;
174 case NiFpga_Status_ResourceNotInitialized:
175 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
176 case NiFpga_Status_HardwareFault:
177 return NiFpga_Status_HardwareFault_MESSAGE;
178 case NiFpga_Status_IrqTimeout:
179 return NiFpga_Status_IrqTimeout_MESSAGE;
180 case SAMPLE_RATE_TOO_HIGH:
181 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
182 case VOLTAGE_OUT_OF_RANGE:
183 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
184 case LOOP_TIMING_ERROR:
185 return LOOP_TIMING_ERROR_MESSAGE;
186 case SPI_WRITE_NO_MOSI:
187 return SPI_WRITE_NO_MOSI_MESSAGE;
188 case SPI_READ_NO_MISO:
189 return SPI_READ_NO_MISO_MESSAGE;
190 case SPI_READ_NO_DATA:
191 return SPI_READ_NO_DATA_MESSAGE;
192 case INCOMPATIBLE_STATE:
193 return INCOMPATIBLE_STATE_MESSAGE;
194 case NO_AVAILABLE_RESOURCES:
195 return NO_AVAILABLE_RESOURCES_MESSAGE;
196 case RESOURCE_IS_ALLOCATED:
197 return RESOURCE_IS_ALLOCATED_MESSAGE;
198 case RESOURCE_OUT_OF_RANGE:
199 return RESOURCE_OUT_OF_RANGE_MESSAGE;
200 case HAL_INVALID_ACCUMULATOR_CHANNEL:
201 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
202 case HAL_HANDLE_ERROR:
203 return HAL_HANDLE_ERROR_MESSAGE;
204 case NULL_PARAMETER:
205 return NULL_PARAMETER_MESSAGE;
206 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
207 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
208 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
209 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
210 case PARAMETER_OUT_OF_RANGE:
211 return PARAMETER_OUT_OF_RANGE_MESSAGE;
212 case HAL_COUNTER_NOT_SUPPORTED:
213 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
214 case HAL_ERR_CANSessionMux_InvalidBuffer:
215 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
216 case HAL_ERR_CANSessionMux_MessageNotFound:
217 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
218 case HAL_WARN_CANSessionMux_NoToken:
219 return WARN_CANSessionMux_NoToken_MESSAGE;
220 case HAL_ERR_CANSessionMux_NotAllowed:
221 return ERR_CANSessionMux_NotAllowed_MESSAGE;
222 case HAL_ERR_CANSessionMux_NotInitialized:
223 return ERR_CANSessionMux_NotInitialized_MESSAGE;
224 case VI_ERROR_SYSTEM_ERROR:
225 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
226 case VI_ERROR_INV_OBJECT:
227 return VI_ERROR_INV_OBJECT_MESSAGE;
228 case VI_ERROR_RSRC_LOCKED:
229 return VI_ERROR_RSRC_LOCKED_MESSAGE;
230 case VI_ERROR_RSRC_NFOUND:
231 return VI_ERROR_RSRC_NFOUND_MESSAGE;
232 case VI_ERROR_INV_RSRC_NAME:
233 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
234 case VI_ERROR_QUEUE_OVERFLOW:
235 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
236 case VI_ERROR_IO:
237 return VI_ERROR_IO_MESSAGE;
238 case VI_ERROR_ASRL_PARITY:
239 return VI_ERROR_ASRL_PARITY_MESSAGE;
240 case VI_ERROR_ASRL_FRAMING:
241 return VI_ERROR_ASRL_FRAMING_MESSAGE;
242 case VI_ERROR_ASRL_OVERRUN:
243 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
244 case VI_ERROR_RSRC_BUSY:
245 return VI_ERROR_RSRC_BUSY_MESSAGE;
246 case VI_ERROR_INV_PARAMETER:
247 return VI_ERROR_INV_PARAMETER_MESSAGE;
248 case HAL_PWM_SCALE_ERROR:
249 return HAL_PWM_SCALE_ERROR_MESSAGE;
250 case HAL_CAN_TIMEOUT:
251 return HAL_CAN_TIMEOUT_MESSAGE;
252 case HAL_SIM_NOT_SUPPORTED:
253 return HAL_SIM_NOT_SUPPORTED_MESSAGE;
254 case HAL_CAN_BUFFER_OVERRUN:
255 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
256 case HAL_LED_CHANNEL_ERROR:
257 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700258 case HAL_USE_LAST_ERROR:
259 return HAL_USE_LAST_ERROR_MESSAGE;
260 case HAL_CONSOLE_OUT_ENABLED_ERROR:
261 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800262 default:
263 return "Unknown error status";
264 }
265}
266
Austin Schuh812d0d12021-11-04 20:16:48 -0700267HAL_RuntimeType HAL_GetRuntimeType(void) {
268 return runtimeType;
269}
Austin Schuh1e69f942020-11-14 15:06:14 -0800270
Austin Schuh812d0d12021-11-04 20:16:48 -0700271void HALSIM_SetRuntimeType(HAL_RuntimeType type) {
272 runtimeType = type;
273}
Brian Silverman8fce7482020-01-05 13:18:21 -0800274
275int32_t HAL_GetFPGAVersion(int32_t* status) {
276 return 2018; // Automatically script this at some point
277}
278
279int64_t HAL_GetFPGARevision(int32_t* status) {
280 return 0; // TODO: Find a better number to return;
281}
282
James Kuszmaulcf324122023-01-14 14:07:17 -0800283size_t HAL_GetSerialNumber(char* buffer, size_t size) {
284 return HALSIM_GetRoboRioSerialNumber(buffer, size);
285}
286
287size_t HAL_GetComments(char* buffer, size_t size) {
288 return HALSIM_GetRoboRioComments(buffer, size);
289}
290
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800291int32_t HAL_GetTeamNumber(void) {
292 return HALSIM_GetRoboRioTeamNumber();
293}
294
Austin Schuh812d0d12021-11-04 20:16:48 -0700295uint64_t HAL_GetFPGATime(int32_t* status) {
296 return hal::GetFPGATime();
297}
Brian Silverman8fce7482020-01-05 13:18:21 -0800298
Austin Schuh812d0d12021-11-04 20:16:48 -0700299uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800300 // Capture the current FPGA time. This will give us the upper half of the
301 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700302 uint64_t fpgaTime = HAL_GetFPGATime(status);
303 if (*status != 0) {
304 return 0;
305 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800306
307 // Now, we need to detect the case where the lower bits rolled over after we
308 // sampled. In that case, the upper bits will be 1 bigger than they should
309 // be.
310
311 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700312 uint32_t lower = fpgaTime & 0xffffffffull;
313 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800314
315 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700316 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800317 --upper;
318 }
319
Austin Schuh812d0d12021-11-04 20:16:48 -0700320 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800321}
322
323HAL_Bool HAL_GetFPGAButton(int32_t* status) {
324 return SimRoboRioData[0].fpgaButton;
325}
326
327HAL_Bool HAL_GetSystemActive(int32_t* status) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800328 return HALSIM_GetDriverStationEnabled();
Brian Silverman8fce7482020-01-05 13:18:21 -0800329}
330
331HAL_Bool HAL_GetBrownedOut(int32_t* status) {
332 return false; // Figure out if we need to detect a brownout condition
333}
334
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800335HAL_Bool HAL_GetRSLState(int32_t* status) {
336 return false;
337}
338
339HAL_Bool HAL_GetSystemTimeValid(int32_t* status) {
340 return true;
341}
342
Brian Silverman8fce7482020-01-05 13:18:21 -0800343HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
344 static std::atomic_bool initialized{false};
345 static wpi::mutex initializeMutex;
346 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700347 if (initialized) {
348 return true;
349 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800350
351 std::scoped_lock lock(initializeMutex);
352 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700353 if (initialized) {
354 return true;
355 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800356
357 hal::init::InitializeHAL();
358
359 hal::init::HAL_IsInitialized.store(true);
360
Brian Silverman8fce7482020-01-05 13:18:21 -0800361 hal::RestartTiming();
James Kuszmaulcf324122023-01-14 14:07:17 -0800362 hal::InitializeDriverStation();
Brian Silverman8fce7482020-01-05 13:18:21 -0800363
364 initialized = true;
Austin Schuh1e69f942020-11-14 15:06:14 -0800365
366// Set Timer Precision to 1ms on Windows
367#ifdef _WIN32
368 TIMECAPS tc;
369 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
370 UINT target = min(1, tc.wPeriodMin);
371 timeBeginPeriod(target);
372 std::atexit([]() {
373 TIMECAPS tc;
374 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
375 UINT target = min(1, tc.wPeriodMin);
376 timeEndPeriod(target);
377 }
378 });
379 }
380#endif // _WIN32
381
Austin Schuh812d0d12021-11-04 20:16:48 -0700382#ifndef _WIN32
383 setlinebuf(stdin);
384 setlinebuf(stdout);
385#endif
386
387 if (HAL_LoadExtensions() < 0) {
388 return false;
389 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800390
Brian Silverman8fce7482020-01-05 13:18:21 -0800391 return true; // Add initialization if we need to at a later point
392}
393
Austin Schuh1e69f942020-11-14 15:06:14 -0800394void HAL_Shutdown(void) {
395 std::vector<std::pair<void*, void (*)(void*)>> funcs;
396 {
397 std::scoped_lock lock(gOnShutdownMutex);
398 funcs.swap(gOnShutdown);
399 }
400 for (auto&& func : funcs) {
401 func.second(func.first);
402 }
403}
404
405void HAL_OnShutdown(void* param, void (*func)(void*)) {
406 std::scoped_lock lock(gOnShutdownMutex);
407 gOnShutdown.emplace_back(param, func);
408}
409
Austin Schuh812d0d12021-11-04 20:16:48 -0700410void HAL_SimPeriodicBefore(void) {
411 gSimPeriodicBefore();
412}
413
414void HAL_SimPeriodicAfter(void) {
415 gSimPeriodicAfter();
416}
417
418int32_t HALSIM_RegisterSimPeriodicBeforeCallback(
419 HALSIM_SimPeriodicCallback callback, void* param) {
420 return gSimPeriodicBefore.Register(callback, param);
421}
422
423void HALSIM_CancelSimPeriodicBeforeCallback(int32_t uid) {
424 gSimPeriodicBefore.Cancel(uid);
425}
426
427int32_t HALSIM_RegisterSimPeriodicAfterCallback(
428 HALSIM_SimPeriodicCallback callback, void* param) {
429 return gSimPeriodicAfter.Register(callback, param);
430}
431
432void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {
433 gSimPeriodicAfter.Cancel(uid);
434}
435
James Kuszmaulcf324122023-01-14 14:07:17 -0800436void HALSIM_CancelAllSimPeriodicCallbacks(void) {
437 gSimPeriodicBefore.Reset();
438 gSimPeriodicAfter.Reset();
439}
440
Brian Silverman8fce7482020-01-05 13:18:21 -0800441int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
442 const char* feature) {
443 return 0; // Do nothing for now
444}
445
446} // extern "C"