blob: 8d911df7feadc4322f5249606d66beeb20eb8dda [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
Austin Schuh812d0d12021-11-04 20:16:48 -070060namespace hal::init {
Brian Silverman8fce7482020-01-05 13:18:21 -080061void InitializeHAL() {
62 InitializeAccelerometerData();
63 InitializeAddressableLEDData();
64 InitializeAnalogGyroData();
65 InitializeAnalogInData();
66 InitializeAnalogOutData();
67 InitializeAnalogTriggerData();
68 InitializeCanData();
69 InitializeCANAPI();
70 InitializeDigitalPWMData();
71 InitializeDutyCycleData();
72 InitializeDIOData();
73 InitializeDriverStationData();
74 InitializeEncoderData();
75 InitializeI2CData();
Austin Schuh812d0d12021-11-04 20:16:48 -070076 InitializeCTREPCMData();
77 InitializeREVPHData();
78 InitializePowerDistributionData();
Brian Silverman8fce7482020-01-05 13:18:21 -080079 InitializePWMData();
80 InitializeRelayData();
81 InitializeRoboRioData();
82 InitializeSimDeviceData();
83 InitializeSPIAccelerometerData();
84 InitializeSPIData();
85 InitializeAccelerometer();
86 InitializeAddressableLED();
87 InitializeAnalogAccumulator();
88 InitializeAnalogGyro();
89 InitializeAnalogInput();
90 InitializeAnalogInternal();
91 InitializeAnalogOutput();
Austin Schuh1e69f942020-11-14 15:06:14 -080092 InitializeAnalogTrigger();
Brian Silverman8fce7482020-01-05 13:18:21 -080093 InitializeCAN();
Brian Silverman8fce7482020-01-05 13:18:21 -080094 InitializeConstants();
95 InitializeCounter();
96 InitializeDigitalInternal();
97 InitializeDIO();
98 InitializeDutyCycle();
99 InitializeDriverStation();
100 InitializeEncoder();
101 InitializeExtensions();
102 InitializeI2C();
103 InitializeInterrupts();
104 InitializeMain();
105 InitializeMockHooks();
106 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -0700107 InitializePowerDistribution();
Brian Silverman8fce7482020-01-05 13:18:21 -0800108 InitializePorts();
109 InitializePower();
Austin Schuh812d0d12021-11-04 20:16:48 -0700110 InitializeCTREPCM();
111 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -0800112 InitializePWM();
113 InitializeRelay();
114 InitializeSerialPort();
115 InitializeSimDevice();
Brian Silverman8fce7482020-01-05 13:18:21 -0800116 InitializeSPI();
117 InitializeThreads();
118}
Austin Schuh812d0d12021-11-04 20:16:48 -0700119} // namespace hal::init
Brian Silverman8fce7482020-01-05 13:18:21 -0800120
121extern "C" {
122
123HAL_PortHandle HAL_GetPort(int32_t channel) {
124 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700125 if (channel < 0 || channel >= 255) {
126 return HAL_kInvalidHandle;
127 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800128 return createPortHandle(channel, 1);
129}
130
131HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
132 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700133 if (channel < 0 || channel >= 255) {
134 return HAL_kInvalidHandle;
135 }
136 if (module < 0 || module >= 255) {
137 return HAL_kInvalidHandle;
138 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800139 return createPortHandle(channel, module);
140}
141
142const char* HAL_GetErrorMessage(int32_t code) {
143 switch (code) {
144 case 0:
145 return "";
146 case CTR_RxTimeout:
147 return CTR_RxTimeout_MESSAGE;
148 case CTR_TxTimeout:
149 return CTR_TxTimeout_MESSAGE;
150 case CTR_InvalidParamValue:
151 return CTR_InvalidParamValue_MESSAGE;
152 case CTR_UnexpectedArbId:
153 return CTR_UnexpectedArbId_MESSAGE;
154 case CTR_TxFailed:
155 return CTR_TxFailed_MESSAGE;
156 case CTR_SigNotUpdated:
157 return CTR_SigNotUpdated_MESSAGE;
158 case NiFpga_Status_FifoTimeout:
159 return NiFpga_Status_FifoTimeout_MESSAGE;
160 case NiFpga_Status_TransferAborted:
161 return NiFpga_Status_TransferAborted_MESSAGE;
162 case NiFpga_Status_MemoryFull:
163 return NiFpga_Status_MemoryFull_MESSAGE;
164 case NiFpga_Status_SoftwareFault:
165 return NiFpga_Status_SoftwareFault_MESSAGE;
166 case NiFpga_Status_InvalidParameter:
167 return NiFpga_Status_InvalidParameter_MESSAGE;
168 case NiFpga_Status_ResourceNotFound:
169 return NiFpga_Status_ResourceNotFound_MESSAGE;
170 case NiFpga_Status_ResourceNotInitialized:
171 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
172 case NiFpga_Status_HardwareFault:
173 return NiFpga_Status_HardwareFault_MESSAGE;
174 case NiFpga_Status_IrqTimeout:
175 return NiFpga_Status_IrqTimeout_MESSAGE;
176 case SAMPLE_RATE_TOO_HIGH:
177 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
178 case VOLTAGE_OUT_OF_RANGE:
179 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
180 case LOOP_TIMING_ERROR:
181 return LOOP_TIMING_ERROR_MESSAGE;
182 case SPI_WRITE_NO_MOSI:
183 return SPI_WRITE_NO_MOSI_MESSAGE;
184 case SPI_READ_NO_MISO:
185 return SPI_READ_NO_MISO_MESSAGE;
186 case SPI_READ_NO_DATA:
187 return SPI_READ_NO_DATA_MESSAGE;
188 case INCOMPATIBLE_STATE:
189 return INCOMPATIBLE_STATE_MESSAGE;
190 case NO_AVAILABLE_RESOURCES:
191 return NO_AVAILABLE_RESOURCES_MESSAGE;
192 case RESOURCE_IS_ALLOCATED:
193 return RESOURCE_IS_ALLOCATED_MESSAGE;
194 case RESOURCE_OUT_OF_RANGE:
195 return RESOURCE_OUT_OF_RANGE_MESSAGE;
196 case HAL_INVALID_ACCUMULATOR_CHANNEL:
197 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
198 case HAL_HANDLE_ERROR:
199 return HAL_HANDLE_ERROR_MESSAGE;
200 case NULL_PARAMETER:
201 return NULL_PARAMETER_MESSAGE;
202 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
203 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
204 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
205 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
206 case PARAMETER_OUT_OF_RANGE:
207 return PARAMETER_OUT_OF_RANGE_MESSAGE;
208 case HAL_COUNTER_NOT_SUPPORTED:
209 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
210 case HAL_ERR_CANSessionMux_InvalidBuffer:
211 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
212 case HAL_ERR_CANSessionMux_MessageNotFound:
213 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
214 case HAL_WARN_CANSessionMux_NoToken:
215 return WARN_CANSessionMux_NoToken_MESSAGE;
216 case HAL_ERR_CANSessionMux_NotAllowed:
217 return ERR_CANSessionMux_NotAllowed_MESSAGE;
218 case HAL_ERR_CANSessionMux_NotInitialized:
219 return ERR_CANSessionMux_NotInitialized_MESSAGE;
220 case VI_ERROR_SYSTEM_ERROR:
221 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
222 case VI_ERROR_INV_OBJECT:
223 return VI_ERROR_INV_OBJECT_MESSAGE;
224 case VI_ERROR_RSRC_LOCKED:
225 return VI_ERROR_RSRC_LOCKED_MESSAGE;
226 case VI_ERROR_RSRC_NFOUND:
227 return VI_ERROR_RSRC_NFOUND_MESSAGE;
228 case VI_ERROR_INV_RSRC_NAME:
229 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
230 case VI_ERROR_QUEUE_OVERFLOW:
231 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
232 case VI_ERROR_IO:
233 return VI_ERROR_IO_MESSAGE;
234 case VI_ERROR_ASRL_PARITY:
235 return VI_ERROR_ASRL_PARITY_MESSAGE;
236 case VI_ERROR_ASRL_FRAMING:
237 return VI_ERROR_ASRL_FRAMING_MESSAGE;
238 case VI_ERROR_ASRL_OVERRUN:
239 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
240 case VI_ERROR_RSRC_BUSY:
241 return VI_ERROR_RSRC_BUSY_MESSAGE;
242 case VI_ERROR_INV_PARAMETER:
243 return VI_ERROR_INV_PARAMETER_MESSAGE;
244 case HAL_PWM_SCALE_ERROR:
245 return HAL_PWM_SCALE_ERROR_MESSAGE;
246 case HAL_CAN_TIMEOUT:
247 return HAL_CAN_TIMEOUT_MESSAGE;
248 case HAL_SIM_NOT_SUPPORTED:
249 return HAL_SIM_NOT_SUPPORTED_MESSAGE;
250 case HAL_CAN_BUFFER_OVERRUN:
251 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
252 case HAL_LED_CHANNEL_ERROR:
253 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700254 case HAL_USE_LAST_ERROR:
255 return HAL_USE_LAST_ERROR_MESSAGE;
256 case HAL_CONSOLE_OUT_ENABLED_ERROR:
257 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800258 default:
259 return "Unknown error status";
260 }
261}
262
Austin Schuh812d0d12021-11-04 20:16:48 -0700263HAL_RuntimeType HAL_GetRuntimeType(void) {
264 return runtimeType;
265}
Austin Schuh1e69f942020-11-14 15:06:14 -0800266
Austin Schuh812d0d12021-11-04 20:16:48 -0700267void HALSIM_SetRuntimeType(HAL_RuntimeType type) {
268 runtimeType = type;
269}
Brian Silverman8fce7482020-01-05 13:18:21 -0800270
271int32_t HAL_GetFPGAVersion(int32_t* status) {
272 return 2018; // Automatically script this at some point
273}
274
275int64_t HAL_GetFPGARevision(int32_t* status) {
276 return 0; // TODO: Find a better number to return;
277}
278
Austin Schuh812d0d12021-11-04 20:16:48 -0700279uint64_t HAL_GetFPGATime(int32_t* status) {
280 return hal::GetFPGATime();
281}
Brian Silverman8fce7482020-01-05 13:18:21 -0800282
Austin Schuh812d0d12021-11-04 20:16:48 -0700283uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800284 // Capture the current FPGA time. This will give us the upper half of the
285 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700286 uint64_t fpgaTime = HAL_GetFPGATime(status);
287 if (*status != 0) {
288 return 0;
289 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800290
291 // Now, we need to detect the case where the lower bits rolled over after we
292 // sampled. In that case, the upper bits will be 1 bigger than they should
293 // be.
294
295 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700296 uint32_t lower = fpgaTime & 0xffffffffull;
297 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800298
299 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700300 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800301 --upper;
302 }
303
Austin Schuh812d0d12021-11-04 20:16:48 -0700304 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800305}
306
307HAL_Bool HAL_GetFPGAButton(int32_t* status) {
308 return SimRoboRioData[0].fpgaButton;
309}
310
311HAL_Bool HAL_GetSystemActive(int32_t* status) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800312 return HALSIM_GetDriverStationEnabled();
Brian Silverman8fce7482020-01-05 13:18:21 -0800313}
314
315HAL_Bool HAL_GetBrownedOut(int32_t* status) {
316 return false; // Figure out if we need to detect a brownout condition
317}
318
319HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
320 static std::atomic_bool initialized{false};
321 static wpi::mutex initializeMutex;
322 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700323 if (initialized) {
324 return true;
325 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800326
327 std::scoped_lock lock(initializeMutex);
328 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700329 if (initialized) {
330 return true;
331 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800332
333 hal::init::InitializeHAL();
334
335 hal::init::HAL_IsInitialized.store(true);
336
Brian Silverman8fce7482020-01-05 13:18:21 -0800337 hal::RestartTiming();
338 HAL_InitializeDriverStation();
339
340 initialized = true;
Austin Schuh1e69f942020-11-14 15:06:14 -0800341
342// Set Timer Precision to 1ms on Windows
343#ifdef _WIN32
344 TIMECAPS tc;
345 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
346 UINT target = min(1, tc.wPeriodMin);
347 timeBeginPeriod(target);
348 std::atexit([]() {
349 TIMECAPS tc;
350 if (timeGetDevCaps(&tc, sizeof(tc)) == TIMERR_NOERROR) {
351 UINT target = min(1, tc.wPeriodMin);
352 timeEndPeriod(target);
353 }
354 });
355 }
356#endif // _WIN32
357
Austin Schuh812d0d12021-11-04 20:16:48 -0700358#ifndef _WIN32
359 setlinebuf(stdin);
360 setlinebuf(stdout);
361#endif
362
363 if (HAL_LoadExtensions() < 0) {
364 return false;
365 }
Austin Schuh1e69f942020-11-14 15:06:14 -0800366
Brian Silverman8fce7482020-01-05 13:18:21 -0800367 return true; // Add initialization if we need to at a later point
368}
369
Austin Schuh1e69f942020-11-14 15:06:14 -0800370void HAL_Shutdown(void) {
371 std::vector<std::pair<void*, void (*)(void*)>> funcs;
372 {
373 std::scoped_lock lock(gOnShutdownMutex);
374 funcs.swap(gOnShutdown);
375 }
376 for (auto&& func : funcs) {
377 func.second(func.first);
378 }
379}
380
381void HAL_OnShutdown(void* param, void (*func)(void*)) {
382 std::scoped_lock lock(gOnShutdownMutex);
383 gOnShutdown.emplace_back(param, func);
384}
385
Austin Schuh812d0d12021-11-04 20:16:48 -0700386void HAL_SimPeriodicBefore(void) {
387 gSimPeriodicBefore();
388}
389
390void HAL_SimPeriodicAfter(void) {
391 gSimPeriodicAfter();
392}
393
394int32_t HALSIM_RegisterSimPeriodicBeforeCallback(
395 HALSIM_SimPeriodicCallback callback, void* param) {
396 return gSimPeriodicBefore.Register(callback, param);
397}
398
399void HALSIM_CancelSimPeriodicBeforeCallback(int32_t uid) {
400 gSimPeriodicBefore.Cancel(uid);
401}
402
403int32_t HALSIM_RegisterSimPeriodicAfterCallback(
404 HALSIM_SimPeriodicCallback callback, void* param) {
405 return gSimPeriodicAfter.Register(callback, param);
406}
407
408void HALSIM_CancelSimPeriodicAfterCallback(int32_t uid) {
409 gSimPeriodicAfter.Cancel(uid);
410}
411
Brian Silverman8fce7482020-01-05 13:18:21 -0800412int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
413 const char* feature) {
414 return 0; // Do nothing for now
415}
416
417} // extern "C"