blob: 3a8cefdcbf7cbd34af7d1a4273cc38df36cc301f [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
7#include <signal.h> // linux for kill
8#include <sys/prctl.h>
9#include <unistd.h>
10
11#include <atomic>
Austin Schuh812d0d12021-11-04 20:16:48 -070012#include <cstdio>
Brian Silverman8fce7482020-01-05 13:18:21 -080013#include <cstdlib>
14#include <fstream>
15#include <thread>
16
17#include <FRC_NetworkCommunication/FRCComm.h>
18#include <FRC_NetworkCommunication/LoadOut.h>
19#include <FRC_NetworkCommunication/UsageReporting.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070020#include <fmt/format.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080021#include <wpi/MemoryBuffer.h>
22#include <wpi/SmallString.h>
23#include <wpi/StringExtras.h>
24#include <wpi/fs.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080025#include <wpi/mutex.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080026#include <wpi/timestamp.h>
27
James Kuszmaulcf324122023-01-14 14:07:17 -080028#include "FPGACalls.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080029#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080030#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080031#include "hal/ChipObject.h"
32#include "hal/DriverStation.h"
33#include "hal/Errors.h"
34#include "hal/Notifier.h"
35#include "hal/handles/HandlesInternal.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080036#include "hal/roborio/InterruptManager.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080037#include "visa/visa.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080038
39using namespace hal;
40
41static std::unique_ptr<tGlobal> global;
42static std::unique_ptr<tSysWatchdog> watchdog;
Austin Schuh75263e32022-02-22 18:05:32 -080043static uint64_t dsStartTime;
Brian Silverman8fce7482020-01-05 13:18:21 -080044
James Kuszmaulcf324122023-01-14 14:07:17 -080045static char roboRioCommentsString[64];
46static size_t roboRioCommentsStringSize;
47static bool roboRioCommentsStringInitialized;
48
Brian Silverman8fce7482020-01-05 13:18:21 -080049using namespace hal;
50
51namespace hal {
James Kuszmaulcf324122023-01-14 14:07:17 -080052void InitializeDriverStation();
Brian Silverman8fce7482020-01-05 13:18:21 -080053namespace init {
54void InitializeHAL() {
Austin Schuh812d0d12021-11-04 20:16:48 -070055 InitializeCTREPCM();
56 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -080057 InitializeAddressableLED();
58 InitializeAccelerometer();
59 InitializeAnalogAccumulator();
Austin Schuh1e69f942020-11-14 15:06:14 -080060 InitializeAnalogGyro();
Brian Silverman8fce7482020-01-05 13:18:21 -080061 InitializeAnalogInput();
62 InitializeAnalogInternal();
63 InitializeAnalogOutput();
64 InitializeAnalogTrigger();
65 InitializeCAN();
66 InitializeCANAPI();
Brian Silverman8fce7482020-01-05 13:18:21 -080067 InitializeConstants();
68 InitializeCounter();
69 InitializeDigitalInternal();
70 InitializeDIO();
71 InitializeDMA();
72 InitializeDutyCycle();
73 InitializeEncoder();
74 InitializeFPGAEncoder();
75 InitializeFRCDriverStation();
76 InitializeI2C();
Austin Schuh1e69f942020-11-14 15:06:14 -080077 InitializeInterrupts();
Brian Silverman8fce7482020-01-05 13:18:21 -080078 InitializeMain();
79 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -070080 InitializeCTREPDP();
81 InitializeREVPDH();
Brian Silverman8fce7482020-01-05 13:18:21 -080082 InitializePorts();
83 InitializePower();
84 InitializePWM();
85 InitializeRelay();
Austin Schuh1e69f942020-11-14 15:06:14 -080086 InitializeSerialPort();
Brian Silverman8fce7482020-01-05 13:18:21 -080087 InitializeSPI();
88 InitializeThreads();
89}
90} // namespace init
Austin Schuh1e69f942020-11-14 15:06:14 -080091
92void ReleaseFPGAInterrupt(int32_t interruptNumber) {
James Kuszmaulcf324122023-01-14 14:07:17 -080093 hal::init::CheckInit();
Austin Schuh1e69f942020-11-14 15:06:14 -080094 if (!global) {
95 return;
96 }
97 int32_t status = 0;
98 global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
99 &status);
100 global->strobeInterruptForceOnce(&status);
101}
Austin Schuh75263e32022-02-22 18:05:32 -0800102
103uint64_t GetDSInitializeTime() {
104 return dsStartTime;
105}
106
Brian Silverman8fce7482020-01-05 13:18:21 -0800107} // namespace hal
108
109extern "C" {
110
111HAL_PortHandle HAL_GetPort(int32_t channel) {
112 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700113 if (channel < 0 || channel >= 255) {
114 return HAL_kInvalidHandle;
115 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800116 return createPortHandle(channel, 1);
117}
118
119HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
120 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700121 if (channel < 0 || channel >= 255) {
122 return HAL_kInvalidHandle;
123 }
124 if (module < 0 || module >= 255) {
125 return HAL_kInvalidHandle;
126 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800127 return createPortHandle(channel, module);
128}
129
130const char* HAL_GetErrorMessage(int32_t code) {
131 switch (code) {
132 case 0:
133 return "";
Brian Silverman8fce7482020-01-05 13:18:21 -0800134 case NiFpga_Status_FifoTimeout:
135 return NiFpga_Status_FifoTimeout_MESSAGE;
136 case NiFpga_Status_TransferAborted:
137 return NiFpga_Status_TransferAborted_MESSAGE;
138 case NiFpga_Status_MemoryFull:
139 return NiFpga_Status_MemoryFull_MESSAGE;
140 case NiFpga_Status_SoftwareFault:
141 return NiFpga_Status_SoftwareFault_MESSAGE;
142 case NiFpga_Status_InvalidParameter:
143 return NiFpga_Status_InvalidParameter_MESSAGE;
144 case NiFpga_Status_ResourceNotFound:
145 return NiFpga_Status_ResourceNotFound_MESSAGE;
146 case NiFpga_Status_ResourceNotInitialized:
147 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
148 case NiFpga_Status_HardwareFault:
149 return NiFpga_Status_HardwareFault_MESSAGE;
150 case NiFpga_Status_IrqTimeout:
151 return NiFpga_Status_IrqTimeout_MESSAGE;
152 case SAMPLE_RATE_TOO_HIGH:
153 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
154 case VOLTAGE_OUT_OF_RANGE:
155 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
156 case LOOP_TIMING_ERROR:
157 return LOOP_TIMING_ERROR_MESSAGE;
158 case SPI_WRITE_NO_MOSI:
159 return SPI_WRITE_NO_MOSI_MESSAGE;
160 case SPI_READ_NO_MISO:
161 return SPI_READ_NO_MISO_MESSAGE;
162 case SPI_READ_NO_DATA:
163 return SPI_READ_NO_DATA_MESSAGE;
164 case INCOMPATIBLE_STATE:
165 return INCOMPATIBLE_STATE_MESSAGE;
166 case NO_AVAILABLE_RESOURCES:
167 return NO_AVAILABLE_RESOURCES_MESSAGE;
168 case RESOURCE_IS_ALLOCATED:
169 return RESOURCE_IS_ALLOCATED_MESSAGE;
170 case RESOURCE_OUT_OF_RANGE:
171 return RESOURCE_OUT_OF_RANGE_MESSAGE;
172 case HAL_INVALID_ACCUMULATOR_CHANNEL:
173 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
174 case HAL_HANDLE_ERROR:
175 return HAL_HANDLE_ERROR_MESSAGE;
176 case NULL_PARAMETER:
177 return NULL_PARAMETER_MESSAGE;
178 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
179 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
180 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
181 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
182 case PARAMETER_OUT_OF_RANGE:
183 return PARAMETER_OUT_OF_RANGE_MESSAGE;
184 case HAL_COUNTER_NOT_SUPPORTED:
185 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
186 case HAL_ERR_CANSessionMux_InvalidBuffer:
187 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
188 case HAL_ERR_CANSessionMux_MessageNotFound:
189 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
190 case HAL_WARN_CANSessionMux_NoToken:
191 return WARN_CANSessionMux_NoToken_MESSAGE;
192 case HAL_ERR_CANSessionMux_NotAllowed:
193 return ERR_CANSessionMux_NotAllowed_MESSAGE;
194 case HAL_ERR_CANSessionMux_NotInitialized:
195 return ERR_CANSessionMux_NotInitialized_MESSAGE;
Austin Schuh1e69f942020-11-14 15:06:14 -0800196 case VI_ERROR_SYSTEM_ERROR:
197 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
198 case VI_ERROR_INV_OBJECT:
199 return VI_ERROR_INV_OBJECT_MESSAGE;
200 case VI_ERROR_RSRC_LOCKED:
201 return VI_ERROR_RSRC_LOCKED_MESSAGE;
202 case VI_ERROR_RSRC_NFOUND:
203 return VI_ERROR_RSRC_NFOUND_MESSAGE;
204 case VI_ERROR_INV_RSRC_NAME:
205 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
206 case VI_ERROR_QUEUE_OVERFLOW:
207 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
208 case VI_ERROR_IO:
209 return VI_ERROR_IO_MESSAGE;
210 case VI_ERROR_ASRL_PARITY:
211 return VI_ERROR_ASRL_PARITY_MESSAGE;
212 case VI_ERROR_ASRL_FRAMING:
213 return VI_ERROR_ASRL_FRAMING_MESSAGE;
214 case VI_ERROR_ASRL_OVERRUN:
215 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
216 case VI_ERROR_RSRC_BUSY:
217 return VI_ERROR_RSRC_BUSY_MESSAGE;
218 case VI_ERROR_INV_PARAMETER:
219 return VI_ERROR_INV_PARAMETER_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800220 case HAL_PWM_SCALE_ERROR:
221 return HAL_PWM_SCALE_ERROR_MESSAGE;
222 case HAL_SERIAL_PORT_NOT_FOUND:
223 return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
224 case HAL_THREAD_PRIORITY_ERROR:
225 return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
226 case HAL_THREAD_PRIORITY_RANGE_ERROR:
227 return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
228 case HAL_SERIAL_PORT_OPEN_ERROR:
229 return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
230 case HAL_SERIAL_PORT_ERROR:
231 return HAL_SERIAL_PORT_ERROR_MESSAGE;
232 case HAL_CAN_TIMEOUT:
233 return HAL_CAN_TIMEOUT_MESSAGE;
234 case ERR_FRCSystem_NetCommNotResponding:
235 return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
236 case ERR_FRCSystem_NoDSConnection:
237 return ERR_FRCSystem_NoDSConnection_MESSAGE;
238 case HAL_CAN_BUFFER_OVERRUN:
239 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
240 case HAL_LED_CHANNEL_ERROR:
241 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700242 case HAL_INVALID_DMA_STATE:
243 return HAL_INVALID_DMA_STATE_MESSAGE;
244 case HAL_INVALID_DMA_ADDITION:
245 return HAL_INVALID_DMA_ADDITION_MESSAGE;
246 case HAL_USE_LAST_ERROR:
247 return HAL_USE_LAST_ERROR_MESSAGE;
248 case HAL_CONSOLE_OUT_ENABLED_ERROR:
249 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800250 default:
251 return "Unknown error status";
252 }
253}
254
Austin Schuh812d0d12021-11-04 20:16:48 -0700255HAL_RuntimeType HAL_GetRuntimeType(void) {
256 nLoadOut::tTargetClass targetClass = nLoadOut::getTargetClass();
257 if (targetClass == nLoadOut::kTargetClass_RoboRIO2) {
258 return HAL_Runtime_RoboRIO2;
259 }
260 return HAL_Runtime_RoboRIO;
261}
Brian Silverman8fce7482020-01-05 13:18:21 -0800262
263int32_t HAL_GetFPGAVersion(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800264 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800265 if (!global) {
266 *status = NiFpga_Status_ResourceNotInitialized;
267 return 0;
268 }
269 return global->readVersion(status);
270}
271
272int64_t HAL_GetFPGARevision(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800273 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800274 if (!global) {
275 *status = NiFpga_Status_ResourceNotInitialized;
276 return 0;
277 }
278 return global->readRevision(status);
279}
280
James Kuszmaulcf324122023-01-14 14:07:17 -0800281size_t HAL_GetSerialNumber(char* buffer, size_t size) {
282 const char* serialNum = std::getenv("serialnum");
283 if (serialNum) {
284 std::strncpy(buffer, serialNum, size);
285 buffer[size - 1] = '\0';
286 return std::strlen(buffer);
287 } else {
288 if (size > 0) {
289 buffer[0] = '\0';
290 }
291 return 0;
292 }
293}
294
295void InitializeRoboRioComments(void) {
296 if (!roboRioCommentsStringInitialized) {
297 std::error_code ec;
298 std::unique_ptr<wpi::MemoryBuffer> fileBuffer =
299 wpi::MemoryBuffer::GetFile("/etc/machine-info", ec);
300
301 std::string_view fileContents;
302 if (fileBuffer && !ec) {
303 fileContents =
304 std::string_view(reinterpret_cast<const char*>(fileBuffer->begin()),
305 fileBuffer->size());
306 } else {
307 roboRioCommentsStringSize = 0;
308 roboRioCommentsStringInitialized = true;
309 return;
310 }
311 std::string_view searchString = "PRETTY_HOSTNAME=\"";
312
313 size_t start = fileContents.find(searchString);
314 if (start == std::string_view::npos) {
315 roboRioCommentsStringSize = 0;
316 roboRioCommentsStringInitialized = true;
317 return;
318 }
319 start += searchString.size();
320 size_t end = fileContents.find("\"", start);
321 if (end == std::string_view::npos) {
322 end = fileContents.size();
323 }
324 std::string_view escapedComments = wpi::slice(fileContents, start, end);
325 wpi::SmallString<64> buf;
326 auto [unescapedComments, rem] = wpi::UnescapeCString(escapedComments, buf);
327 unescapedComments.copy(roboRioCommentsString,
328 sizeof(roboRioCommentsString));
329
330 if (unescapedComments.size() > sizeof(roboRioCommentsString)) {
331 roboRioCommentsStringSize = sizeof(roboRioCommentsString);
332 } else {
333 roboRioCommentsStringSize = unescapedComments.size();
334 }
335 roboRioCommentsStringInitialized = true;
336 }
337}
338
339size_t HAL_GetComments(char* buffer, size_t size) {
340 if (!roboRioCommentsStringInitialized) {
341 InitializeRoboRioComments();
342 }
343 size_t toCopy = size;
344 if (size > roboRioCommentsStringSize) {
345 toCopy = roboRioCommentsStringSize;
346 }
347 std::memcpy(buffer, roboRioCommentsString, toCopy);
348 if (toCopy < size) {
349 buffer[toCopy] = '\0';
350 } else {
351 buffer[toCopy - 1] = '\0';
352 }
353 return toCopy;
354}
355
Brian Silverman8fce7482020-01-05 13:18:21 -0800356uint64_t HAL_GetFPGATime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800357 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800358 if (!global) {
359 *status = NiFpga_Status_ResourceNotInitialized;
360 return 0;
361 }
362 *status = 0;
363 uint64_t upper1 = global->readLocalTimeUpper(status);
364 uint32_t lower = global->readLocalTime(status);
365 uint64_t upper2 = global->readLocalTimeUpper(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700366 if (*status != 0) {
367 return 0;
368 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800369 if (upper1 != upper2) {
370 // Rolled over between the lower call, reread lower
371 lower = global->readLocalTime(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700372 if (*status != 0) {
373 return 0;
374 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800375 }
376 return (upper2 << 32) + lower;
377}
378
Austin Schuh812d0d12021-11-04 20:16:48 -0700379uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800380 // Capture the current FPGA time. This will give us the upper half of the
381 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700382 uint64_t fpgaTime = HAL_GetFPGATime(status);
383 if (*status != 0) {
384 return 0;
385 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800386
387 // Now, we need to detect the case where the lower bits rolled over after we
388 // sampled. In that case, the upper bits will be 1 bigger than they should
389 // be.
390
391 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700392 uint32_t lower = fpgaTime & 0xffffffffull;
393 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800394
395 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700396 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800397 --upper;
398 }
399
Austin Schuh812d0d12021-11-04 20:16:48 -0700400 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800401}
402
403HAL_Bool HAL_GetFPGAButton(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800404 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800405 if (!global) {
406 *status = NiFpga_Status_ResourceNotInitialized;
407 return false;
408 }
409 return global->readUserButton(status);
410}
411
412HAL_Bool HAL_GetSystemActive(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800413 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800414 if (!watchdog) {
415 *status = NiFpga_Status_ResourceNotInitialized;
416 return false;
417 }
418 return watchdog->readStatus_SystemActive(status);
419}
420
421HAL_Bool HAL_GetBrownedOut(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800422 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800423 if (!watchdog) {
424 *status = NiFpga_Status_ResourceNotInitialized;
425 return false;
426 }
427 return !(watchdog->readStatus_PowerAlive(status));
428}
429
430static bool killExistingProgram(int timeout, int mode) {
431 // Kill any previous robot programs
432 std::fstream fs;
433 // By making this both in/out, it won't give us an error if it doesnt exist
434 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
Austin Schuh812d0d12021-11-04 20:16:48 -0700435 if (fs.bad()) {
436 return false;
437 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800438
439 pid_t pid = 0;
440 if (!fs.eof() && !fs.fail()) {
441 fs >> pid;
442 // see if the pid is around, but we don't want to mess with init id=1, or
443 // ourselves
444 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700445 std::puts("Killing previously running FRC program...");
Brian Silverman8fce7482020-01-05 13:18:21 -0800446 kill(pid, SIGTERM); // try to kill it
447 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
448 if (kill(pid, 0) == 0) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800449 // still not successful
Austin Schuh812d0d12021-11-04 20:16:48 -0700450 fmt::print(
451 "FRC pid {} did not die within {} ms. Force killing with kill -9\n",
452 pid, timeout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800453 // Force kill -9
454 auto forceKill = kill(pid, SIGKILL);
455 if (forceKill != 0) {
456 auto errorMsg = std::strerror(forceKill);
Austin Schuh812d0d12021-11-04 20:16:48 -0700457 fmt::print("Kill -9 error: {}\n", errorMsg);
Brian Silverman8fce7482020-01-05 13:18:21 -0800458 }
459 // Give a bit of time for the kill to take place
460 std::this_thread::sleep_for(std::chrono::milliseconds(250));
461 }
462 }
463 }
464 fs.close();
465 // we will re-open it write only to truncate the file
466 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
467 fs.seekp(0);
468 pid = getpid();
469 fs << pid << std::endl;
470 fs.close();
471 return true;
472}
473
474HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
475 static std::atomic_bool initialized{false};
476 static wpi::mutex initializeMutex;
477 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700478 if (initialized) {
479 return true;
480 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800481
482 std::scoped_lock lock(initializeMutex);
483 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700484 if (initialized) {
485 return true;
486 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800487
James Kuszmaulcf324122023-01-14 14:07:17 -0800488 int fpgaInit = hal::init::InitializeFPGA();
489 if (fpgaInit != HAL_SUCCESS) {
490 return false;
491 }
492
Brian Silverman8fce7482020-01-05 13:18:21 -0800493 hal::init::InitializeHAL();
494
495 hal::init::HAL_IsInitialized.store(true);
496
497 setlinebuf(stdin);
498 setlinebuf(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800499
500 prctl(PR_SET_PDEATHSIG, SIGTERM);
501
502 // Return false if program failed to kill an existing program
503 if (!killExistingProgram(timeout, mode)) {
504 return false;
505 }
506
507 FRC_NetworkCommunication_Reserve(nullptr);
508
509 std::atexit([]() {
510 // Unregister our new data condition variable.
511 setNewDataSem(nullptr);
512 });
513
Brian Silverman8fce7482020-01-05 13:18:21 -0800514 nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
Austin Schuh1e69f942020-11-14 15:06:14 -0800515 nLoadOut::getTargetClass();
Brian Silverman8fce7482020-01-05 13:18:21 -0800516
517 int32_t status = 0;
518 global.reset(tGlobal::create(&status));
519 watchdog.reset(tSysWatchdog::create(&status));
520
Austin Schuh812d0d12021-11-04 20:16:48 -0700521 if (status != 0) {
522 return false;
523 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800524
James Kuszmaulcf324122023-01-14 14:07:17 -0800525 InterruptManager::Initialize(global->getSystemInterface());
526
527 hal::InitializeDriverStation();
Brian Silverman8fce7482020-01-05 13:18:21 -0800528
Austin Schuh75263e32022-02-22 18:05:32 -0800529 dsStartTime = HAL_GetFPGATime(&status);
530 if (status != 0) {
531 return false;
532 }
533
Brian Silverman8fce7482020-01-05 13:18:21 -0800534 // Set WPI_Now to use FPGA timestamp
535 wpi::SetNowImpl([]() -> uint64_t {
536 int32_t status = 0;
537 uint64_t rv = HAL_GetFPGATime(&status);
538 if (status != 0) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700539 fmt::print(stderr,
540 "Call to HAL_GetFPGATime failed in wpi::Now() with status {}. "
541 "Initialization might have failed. Time will not be correct\n",
542 status);
543 std::fflush(stderr);
Brian Silverman8fce7482020-01-05 13:18:21 -0800544 return 0u;
545 }
546 return rv;
547 });
548
549 initialized = true;
550 return true;
551}
552
Austin Schuh1e69f942020-11-14 15:06:14 -0800553void HAL_Shutdown(void) {}
554
Austin Schuh812d0d12021-11-04 20:16:48 -0700555void HAL_SimPeriodicBefore(void) {}
556
557void HAL_SimPeriodicAfter(void) {}
558
Brian Silverman8fce7482020-01-05 13:18:21 -0800559int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
560 const char* feature) {
561 if (feature == nullptr) {
562 feature = "";
563 }
564
565 return FRC_NetworkCommunication_nUsageReporting_report(
566 resource, instanceNumber, context, feature);
567}
568
Brian Silverman8fce7482020-01-05 13:18:21 -0800569} // extern "C"