blob: f239391b360fc5960424ecca6e97f7d76806cf18 [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
Maxwell Henderson80bec322024-01-09 15:48:44 -08007#include <dlfcn.h>
Brian Silverman8fce7482020-01-05 13:18:21 -08008#include <signal.h> // linux for kill
9#include <sys/prctl.h>
10#include <unistd.h>
11
12#include <atomic>
Austin Schuh812d0d12021-11-04 20:16:48 -070013#include <cstdio>
Brian Silverman8fce7482020-01-05 13:18:21 -080014#include <cstdlib>
15#include <fstream>
16#include <thread>
17
18#include <FRC_NetworkCommunication/FRCComm.h>
19#include <FRC_NetworkCommunication/LoadOut.h>
20#include <FRC_NetworkCommunication/UsageReporting.h>
Austin Schuh812d0d12021-11-04 20:16:48 -070021#include <fmt/format.h>
James Kuszmaulcf324122023-01-14 14:07:17 -080022#include <wpi/MemoryBuffer.h>
23#include <wpi/SmallString.h>
24#include <wpi/StringExtras.h>
25#include <wpi/fs.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080026#include <wpi/mutex.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080027#include <wpi/timestamp.h>
28
James Kuszmaulcf324122023-01-14 14:07:17 -080029#include "FPGACalls.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080030#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080031#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080032#include "hal/ChipObject.h"
33#include "hal/DriverStation.h"
34#include "hal/Errors.h"
35#include "hal/Notifier.h"
36#include "hal/handles/HandlesInternal.h"
James Kuszmaulb13e13f2023-11-22 20:44:04 -080037#include "hal/roborio/HMB.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080038#include "hal/roborio/InterruptManager.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080039#include "visa/visa.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080040
41using namespace hal;
42
43static std::unique_ptr<tGlobal> global;
44static std::unique_ptr<tSysWatchdog> watchdog;
Austin Schuh75263e32022-02-22 18:05:32 -080045static uint64_t dsStartTime;
Brian Silverman8fce7482020-01-05 13:18:21 -080046
James Kuszmaulcf324122023-01-14 14:07:17 -080047static char roboRioCommentsString[64];
48static size_t roboRioCommentsStringSize;
49static bool roboRioCommentsStringInitialized;
50
James Kuszmaulb13e13f2023-11-22 20:44:04 -080051static int32_t teamNumber = -1;
52
53static const volatile HAL_HMBData* hmbBuffer;
54#define HAL_HMB_TIMESTAMP_OFFSET 5
55
Brian Silverman8fce7482020-01-05 13:18:21 -080056using namespace hal;
57
58namespace hal {
James Kuszmaulcf324122023-01-14 14:07:17 -080059void InitializeDriverStation();
James Kuszmaulb13e13f2023-11-22 20:44:04 -080060void WaitForInitialPacket();
Brian Silverman8fce7482020-01-05 13:18:21 -080061namespace init {
62void InitializeHAL() {
Austin Schuh812d0d12021-11-04 20:16:48 -070063 InitializeCTREPCM();
64 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -080065 InitializeAddressableLED();
66 InitializeAccelerometer();
67 InitializeAnalogAccumulator();
Austin Schuh1e69f942020-11-14 15:06:14 -080068 InitializeAnalogGyro();
Brian Silverman8fce7482020-01-05 13:18:21 -080069 InitializeAnalogInput();
70 InitializeAnalogInternal();
71 InitializeAnalogOutput();
72 InitializeAnalogTrigger();
73 InitializeCAN();
74 InitializeCANAPI();
Brian Silverman8fce7482020-01-05 13:18:21 -080075 InitializeConstants();
76 InitializeCounter();
77 InitializeDigitalInternal();
78 InitializeDIO();
79 InitializeDMA();
80 InitializeDutyCycle();
81 InitializeEncoder();
82 InitializeFPGAEncoder();
83 InitializeFRCDriverStation();
84 InitializeI2C();
Austin Schuh1e69f942020-11-14 15:06:14 -080085 InitializeInterrupts();
Maxwell Henderson80bec322024-01-09 15:48:44 -080086 InitializeLEDs();
Brian Silverman8fce7482020-01-05 13:18:21 -080087 InitializeMain();
88 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -070089 InitializeCTREPDP();
90 InitializeREVPDH();
Brian Silverman8fce7482020-01-05 13:18:21 -080091 InitializePorts();
92 InitializePower();
93 InitializePWM();
94 InitializeRelay();
Austin Schuh1e69f942020-11-14 15:06:14 -080095 InitializeSerialPort();
Brian Silverman8fce7482020-01-05 13:18:21 -080096 InitializeSPI();
97 InitializeThreads();
98}
99} // namespace init
Austin Schuh1e69f942020-11-14 15:06:14 -0800100
101void ReleaseFPGAInterrupt(int32_t interruptNumber) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800102 hal::init::CheckInit();
Austin Schuh1e69f942020-11-14 15:06:14 -0800103 if (!global) {
104 return;
105 }
106 int32_t status = 0;
107 global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
108 &status);
109 global->strobeInterruptForceOnce(&status);
110}
Austin Schuh75263e32022-02-22 18:05:32 -0800111
112uint64_t GetDSInitializeTime() {
113 return dsStartTime;
114}
115
Brian Silverman8fce7482020-01-05 13:18:21 -0800116} // namespace hal
117
118extern "C" {
119
120HAL_PortHandle HAL_GetPort(int32_t channel) {
121 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700122 if (channel < 0 || channel >= 255) {
123 return HAL_kInvalidHandle;
124 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800125 return createPortHandle(channel, 1);
126}
127
128HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
129 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700130 if (channel < 0 || channel >= 255) {
131 return HAL_kInvalidHandle;
132 }
133 if (module < 0 || module >= 255) {
134 return HAL_kInvalidHandle;
135 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800136 return createPortHandle(channel, module);
137}
138
139const char* HAL_GetErrorMessage(int32_t code) {
140 switch (code) {
141 case 0:
142 return "";
Brian Silverman8fce7482020-01-05 13:18:21 -0800143 case NiFpga_Status_FifoTimeout:
144 return NiFpga_Status_FifoTimeout_MESSAGE;
145 case NiFpga_Status_TransferAborted:
146 return NiFpga_Status_TransferAborted_MESSAGE;
147 case NiFpga_Status_MemoryFull:
148 return NiFpga_Status_MemoryFull_MESSAGE;
149 case NiFpga_Status_SoftwareFault:
150 return NiFpga_Status_SoftwareFault_MESSAGE;
151 case NiFpga_Status_InvalidParameter:
152 return NiFpga_Status_InvalidParameter_MESSAGE;
153 case NiFpga_Status_ResourceNotFound:
154 return NiFpga_Status_ResourceNotFound_MESSAGE;
155 case NiFpga_Status_ResourceNotInitialized:
156 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
157 case NiFpga_Status_HardwareFault:
158 return NiFpga_Status_HardwareFault_MESSAGE;
159 case NiFpga_Status_IrqTimeout:
160 return NiFpga_Status_IrqTimeout_MESSAGE;
161 case SAMPLE_RATE_TOO_HIGH:
162 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
163 case VOLTAGE_OUT_OF_RANGE:
164 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
165 case LOOP_TIMING_ERROR:
166 return LOOP_TIMING_ERROR_MESSAGE;
167 case SPI_WRITE_NO_MOSI:
168 return SPI_WRITE_NO_MOSI_MESSAGE;
169 case SPI_READ_NO_MISO:
170 return SPI_READ_NO_MISO_MESSAGE;
171 case SPI_READ_NO_DATA:
172 return SPI_READ_NO_DATA_MESSAGE;
173 case INCOMPATIBLE_STATE:
174 return INCOMPATIBLE_STATE_MESSAGE;
175 case NO_AVAILABLE_RESOURCES:
176 return NO_AVAILABLE_RESOURCES_MESSAGE;
177 case RESOURCE_IS_ALLOCATED:
178 return RESOURCE_IS_ALLOCATED_MESSAGE;
179 case RESOURCE_OUT_OF_RANGE:
180 return RESOURCE_OUT_OF_RANGE_MESSAGE;
181 case HAL_INVALID_ACCUMULATOR_CHANNEL:
182 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
183 case HAL_HANDLE_ERROR:
184 return HAL_HANDLE_ERROR_MESSAGE;
185 case NULL_PARAMETER:
186 return NULL_PARAMETER_MESSAGE;
187 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
188 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
189 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
190 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
191 case PARAMETER_OUT_OF_RANGE:
192 return PARAMETER_OUT_OF_RANGE_MESSAGE;
193 case HAL_COUNTER_NOT_SUPPORTED:
194 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
195 case HAL_ERR_CANSessionMux_InvalidBuffer:
196 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
197 case HAL_ERR_CANSessionMux_MessageNotFound:
198 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
199 case HAL_WARN_CANSessionMux_NoToken:
200 return WARN_CANSessionMux_NoToken_MESSAGE;
201 case HAL_ERR_CANSessionMux_NotAllowed:
202 return ERR_CANSessionMux_NotAllowed_MESSAGE;
203 case HAL_ERR_CANSessionMux_NotInitialized:
204 return ERR_CANSessionMux_NotInitialized_MESSAGE;
Austin Schuh1e69f942020-11-14 15:06:14 -0800205 case VI_ERROR_SYSTEM_ERROR:
206 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
207 case VI_ERROR_INV_OBJECT:
208 return VI_ERROR_INV_OBJECT_MESSAGE;
209 case VI_ERROR_RSRC_LOCKED:
210 return VI_ERROR_RSRC_LOCKED_MESSAGE;
211 case VI_ERROR_RSRC_NFOUND:
212 return VI_ERROR_RSRC_NFOUND_MESSAGE;
213 case VI_ERROR_INV_RSRC_NAME:
214 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
215 case VI_ERROR_QUEUE_OVERFLOW:
216 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
217 case VI_ERROR_IO:
218 return VI_ERROR_IO_MESSAGE;
219 case VI_ERROR_ASRL_PARITY:
220 return VI_ERROR_ASRL_PARITY_MESSAGE;
221 case VI_ERROR_ASRL_FRAMING:
222 return VI_ERROR_ASRL_FRAMING_MESSAGE;
223 case VI_ERROR_ASRL_OVERRUN:
224 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
225 case VI_ERROR_RSRC_BUSY:
226 return VI_ERROR_RSRC_BUSY_MESSAGE;
227 case VI_ERROR_INV_PARAMETER:
228 return VI_ERROR_INV_PARAMETER_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800229 case HAL_PWM_SCALE_ERROR:
230 return HAL_PWM_SCALE_ERROR_MESSAGE;
231 case HAL_SERIAL_PORT_NOT_FOUND:
232 return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
233 case HAL_THREAD_PRIORITY_ERROR:
234 return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
235 case HAL_THREAD_PRIORITY_RANGE_ERROR:
236 return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
237 case HAL_SERIAL_PORT_OPEN_ERROR:
238 return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
239 case HAL_SERIAL_PORT_ERROR:
240 return HAL_SERIAL_PORT_ERROR_MESSAGE;
241 case HAL_CAN_TIMEOUT:
242 return HAL_CAN_TIMEOUT_MESSAGE;
243 case ERR_FRCSystem_NetCommNotResponding:
244 return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
245 case ERR_FRCSystem_NoDSConnection:
246 return ERR_FRCSystem_NoDSConnection_MESSAGE;
247 case HAL_CAN_BUFFER_OVERRUN:
248 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
249 case HAL_LED_CHANNEL_ERROR:
250 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700251 case HAL_INVALID_DMA_STATE:
252 return HAL_INVALID_DMA_STATE_MESSAGE;
253 case HAL_INVALID_DMA_ADDITION:
254 return HAL_INVALID_DMA_ADDITION_MESSAGE;
255 case HAL_USE_LAST_ERROR:
256 return HAL_USE_LAST_ERROR_MESSAGE;
257 case HAL_CONSOLE_OUT_ENABLED_ERROR:
258 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800259 default:
260 return "Unknown error status";
261 }
262}
263
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800264static HAL_RuntimeType runtimeType = HAL_Runtime_RoboRIO;
265
Austin Schuh812d0d12021-11-04 20:16:48 -0700266HAL_RuntimeType HAL_GetRuntimeType(void) {
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800267 return runtimeType;
Austin Schuh812d0d12021-11-04 20:16:48 -0700268}
Brian Silverman8fce7482020-01-05 13:18:21 -0800269
270int32_t HAL_GetFPGAVersion(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800271 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800272 if (!global) {
273 *status = NiFpga_Status_ResourceNotInitialized;
274 return 0;
275 }
276 return global->readVersion(status);
277}
278
279int64_t HAL_GetFPGARevision(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800280 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800281 if (!global) {
282 *status = NiFpga_Status_ResourceNotInitialized;
283 return 0;
284 }
285 return global->readRevision(status);
286}
287
James Kuszmaulcf324122023-01-14 14:07:17 -0800288size_t HAL_GetSerialNumber(char* buffer, size_t size) {
289 const char* serialNum = std::getenv("serialnum");
290 if (serialNum) {
291 std::strncpy(buffer, serialNum, size);
292 buffer[size - 1] = '\0';
293 return std::strlen(buffer);
294 } else {
295 if (size > 0) {
296 buffer[0] = '\0';
297 }
298 return 0;
299 }
300}
301
302void InitializeRoboRioComments(void) {
303 if (!roboRioCommentsStringInitialized) {
304 std::error_code ec;
305 std::unique_ptr<wpi::MemoryBuffer> fileBuffer =
306 wpi::MemoryBuffer::GetFile("/etc/machine-info", ec);
307
308 std::string_view fileContents;
309 if (fileBuffer && !ec) {
310 fileContents =
311 std::string_view(reinterpret_cast<const char*>(fileBuffer->begin()),
312 fileBuffer->size());
313 } else {
314 roboRioCommentsStringSize = 0;
315 roboRioCommentsStringInitialized = true;
316 return;
317 }
318 std::string_view searchString = "PRETTY_HOSTNAME=\"";
319
320 size_t start = fileContents.find(searchString);
321 if (start == std::string_view::npos) {
322 roboRioCommentsStringSize = 0;
323 roboRioCommentsStringInitialized = true;
324 return;
325 }
326 start += searchString.size();
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800327 std::string_view escapedComments =
328 wpi::slice(fileContents, start, fileContents.size());
James Kuszmaulcf324122023-01-14 14:07:17 -0800329 wpi::SmallString<64> buf;
330 auto [unescapedComments, rem] = wpi::UnescapeCString(escapedComments, buf);
331 unescapedComments.copy(roboRioCommentsString,
332 sizeof(roboRioCommentsString));
333
334 if (unescapedComments.size() > sizeof(roboRioCommentsString)) {
335 roboRioCommentsStringSize = sizeof(roboRioCommentsString);
336 } else {
337 roboRioCommentsStringSize = unescapedComments.size();
338 }
339 roboRioCommentsStringInitialized = true;
340 }
341}
342
343size_t HAL_GetComments(char* buffer, size_t size) {
344 if (!roboRioCommentsStringInitialized) {
345 InitializeRoboRioComments();
346 }
347 size_t toCopy = size;
348 if (size > roboRioCommentsStringSize) {
349 toCopy = roboRioCommentsStringSize;
350 }
351 std::memcpy(buffer, roboRioCommentsString, toCopy);
352 if (toCopy < size) {
353 buffer[toCopy] = '\0';
354 } else {
355 buffer[toCopy - 1] = '\0';
356 }
357 return toCopy;
358}
359
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800360void InitializeTeamNumber(void) {
361 char hostnameBuf[25];
362 auto status = gethostname(hostnameBuf, sizeof(hostnameBuf));
363 if (status != 0) {
364 teamNumber = 0;
365 return;
366 }
367
368 std::string_view hostname{hostnameBuf, sizeof(hostnameBuf)};
369
370 // hostname is frc-{TEAM}-roborio
371 // Split string around '-' (max of 2 splits), take the second element of the
372 // resulting array.
373 wpi::SmallVector<std::string_view> elements;
374 wpi::split(hostname, elements, "-", 2);
375 if (elements.size() < 3) {
376 teamNumber = 0;
377 return;
378 }
379
380 teamNumber = wpi::parse_integer<int32_t>(elements[1], 10).value_or(0);
381}
382
383int32_t HAL_GetTeamNumber(void) {
384 if (teamNumber == -1) {
385 InitializeTeamNumber();
386 }
387 return teamNumber;
388}
389
Brian Silverman8fce7482020-01-05 13:18:21 -0800390uint64_t HAL_GetFPGATime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800391 hal::init::CheckInit();
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800392 if (!hmbBuffer) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800393 *status = NiFpga_Status_ResourceNotInitialized;
394 return 0;
395 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800396
397 asm("dmb");
398 uint64_t upper1 = hmbBuffer->Timestamp.Upper;
399 asm("dmb");
400 uint32_t lower = hmbBuffer->Timestamp.Lower;
401 asm("dmb");
402 uint64_t upper2 = hmbBuffer->Timestamp.Upper;
403
Brian Silverman8fce7482020-01-05 13:18:21 -0800404 if (upper1 != upper2) {
405 // Rolled over between the lower call, reread lower
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800406 asm("dmb");
407 lower = hmbBuffer->Timestamp.Lower;
Brian Silverman8fce7482020-01-05 13:18:21 -0800408 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800409 // 5 is added here because the time to write from the FPGA
410 // to the HMB buffer is longer then the time to read
411 // from the time register. This would cause register based
412 // timestamps to be ahead of HMB timestamps, which could
413 // be very bad.
414 return (upper2 << 32) + lower + HAL_HMB_TIMESTAMP_OFFSET;
Brian Silverman8fce7482020-01-05 13:18:21 -0800415}
416
Austin Schuh812d0d12021-11-04 20:16:48 -0700417uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800418 // Capture the current FPGA time. This will give us the upper half of the
419 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700420 uint64_t fpgaTime = HAL_GetFPGATime(status);
421 if (*status != 0) {
422 return 0;
423 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800424
425 // Now, we need to detect the case where the lower bits rolled over after we
426 // sampled. In that case, the upper bits will be 1 bigger than they should
427 // be.
428
429 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700430 uint32_t lower = fpgaTime & 0xffffffffull;
431 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800432
433 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700434 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800435 --upper;
436 }
437
Austin Schuh812d0d12021-11-04 20:16:48 -0700438 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800439}
440
441HAL_Bool HAL_GetFPGAButton(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800442 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800443 if (!global) {
444 *status = NiFpga_Status_ResourceNotInitialized;
445 return false;
446 }
447 return global->readUserButton(status);
448}
449
450HAL_Bool HAL_GetSystemActive(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800451 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800452 if (!watchdog) {
453 *status = NiFpga_Status_ResourceNotInitialized;
454 return false;
455 }
456 return watchdog->readStatus_SystemActive(status);
457}
458
459HAL_Bool HAL_GetBrownedOut(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800460 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800461 if (!watchdog) {
462 *status = NiFpga_Status_ResourceNotInitialized;
463 return false;
464 }
465 return !(watchdog->readStatus_PowerAlive(status));
466}
467
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800468HAL_Bool HAL_GetRSLState(int32_t* status) {
469 hal::init::CheckInit();
470 if (!global) {
471 *status = NiFpga_Status_ResourceNotInitialized;
472 return false;
473 }
474 return global->readLEDs_RSL(status);
475}
476
477HAL_Bool HAL_GetSystemTimeValid(int32_t* status) {
478 uint8_t timeWasSet = 0;
479 *status = FRC_NetworkCommunication_getTimeWasSet(&timeWasSet);
480 return timeWasSet != 0;
481}
482
Brian Silverman8fce7482020-01-05 13:18:21 -0800483static bool killExistingProgram(int timeout, int mode) {
484 // Kill any previous robot programs
485 std::fstream fs;
486 // By making this both in/out, it won't give us an error if it doesnt exist
487 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
Austin Schuh812d0d12021-11-04 20:16:48 -0700488 if (fs.bad()) {
489 return false;
490 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800491
492 pid_t pid = 0;
493 if (!fs.eof() && !fs.fail()) {
494 fs >> pid;
495 // see if the pid is around, but we don't want to mess with init id=1, or
496 // ourselves
497 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700498 std::puts("Killing previously running FRC program...");
Brian Silverman8fce7482020-01-05 13:18:21 -0800499 kill(pid, SIGTERM); // try to kill it
500 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
501 if (kill(pid, 0) == 0) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800502 // still not successful
Austin Schuh812d0d12021-11-04 20:16:48 -0700503 fmt::print(
504 "FRC pid {} did not die within {} ms. Force killing with kill -9\n",
505 pid, timeout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800506 // Force kill -9
507 auto forceKill = kill(pid, SIGKILL);
508 if (forceKill != 0) {
509 auto errorMsg = std::strerror(forceKill);
Austin Schuh812d0d12021-11-04 20:16:48 -0700510 fmt::print("Kill -9 error: {}\n", errorMsg);
Brian Silverman8fce7482020-01-05 13:18:21 -0800511 }
512 // Give a bit of time for the kill to take place
513 std::this_thread::sleep_for(std::chrono::milliseconds(250));
514 }
515 }
516 }
517 fs.close();
518 // we will re-open it write only to truncate the file
519 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
520 fs.seekp(0);
521 pid = getpid();
522 fs << pid << std::endl;
523 fs.close();
524 return true;
525}
526
Maxwell Henderson80bec322024-01-09 15:48:44 -0800527static void SetupNowRio(void) {
528 nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
529 nLoadOut::getTargetClass();
530
531 int32_t status = 0;
532
533 Dl_info info;
534 status = dladdr(reinterpret_cast<void*>(tHMB::create), &info);
535 if (status == 0) {
536 fmt::print(stderr, "Failed to call dladdr on chipobject {}\n", dlerror());
537 return;
538 }
539
540 void* chipObjectLibrary = dlopen(info.dli_fname, RTLD_LAZY);
541 if (chipObjectLibrary == nullptr) {
542 fmt::print(stderr, "Failed to call dlopen on chipobject {}\n", dlerror());
543 return;
544 }
545
546 std::unique_ptr<tHMB> hmb;
547 hmb.reset(tHMB::create(&status));
548 if (hmb == nullptr) {
549 fmt::print(stderr, "Failed to open HMB on chipobject {}\n", status);
550 dlclose(chipObjectLibrary);
551 return;
552 }
553 wpi::impl::SetupNowRio(chipObjectLibrary, std::move(hmb));
554}
555
Brian Silverman8fce7482020-01-05 13:18:21 -0800556HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
557 static std::atomic_bool initialized{false};
558 static wpi::mutex initializeMutex;
559 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700560 if (initialized) {
561 return true;
562 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800563
564 std::scoped_lock lock(initializeMutex);
565 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700566 if (initialized) {
567 return true;
568 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800569
James Kuszmaulcf324122023-01-14 14:07:17 -0800570 int fpgaInit = hal::init::InitializeFPGA();
571 if (fpgaInit != HAL_SUCCESS) {
572 return false;
573 }
574
Brian Silverman8fce7482020-01-05 13:18:21 -0800575 hal::init::InitializeHAL();
576
577 hal::init::HAL_IsInitialized.store(true);
578
579 setlinebuf(stdin);
580 setlinebuf(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800581
582 prctl(PR_SET_PDEATHSIG, SIGTERM);
583
584 // Return false if program failed to kill an existing program
585 if (!killExistingProgram(timeout, mode)) {
586 return false;
587 }
588
589 FRC_NetworkCommunication_Reserve(nullptr);
590
591 std::atexit([]() {
592 // Unregister our new data condition variable.
593 setNewDataSem(nullptr);
594 });
595
Maxwell Henderson80bec322024-01-09 15:48:44 -0800596 SetupNowRio();
Brian Silverman8fce7482020-01-05 13:18:21 -0800597
598 int32_t status = 0;
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800599
600 HAL_InitializeHMB(&status);
601 if (status != 0) {
Maxwell Henderson80bec322024-01-09 15:48:44 -0800602 fmt::print(stderr, "Failed to open HAL HMB, status code {}\n", status);
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800603 return false;
604 }
605 hmbBuffer = HAL_GetHMBBuffer();
606
Brian Silverman8fce7482020-01-05 13:18:21 -0800607 global.reset(tGlobal::create(&status));
608 watchdog.reset(tSysWatchdog::create(&status));
609
Austin Schuh812d0d12021-11-04 20:16:48 -0700610 if (status != 0) {
611 return false;
612 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800613
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800614 nLoadOut::tTargetClass targetClass = nLoadOut::getTargetClass();
615 if (targetClass == nLoadOut::kTargetClass_RoboRIO2) {
616 runtimeType = HAL_Runtime_RoboRIO2;
617 } else {
618 runtimeType = HAL_Runtime_RoboRIO;
619 }
620
James Kuszmaulcf324122023-01-14 14:07:17 -0800621 InterruptManager::Initialize(global->getSystemInterface());
622
623 hal::InitializeDriverStation();
Brian Silverman8fce7482020-01-05 13:18:21 -0800624
Austin Schuh75263e32022-02-22 18:05:32 -0800625 dsStartTime = HAL_GetFPGATime(&status);
626 if (status != 0) {
627 return false;
628 }
629
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800630 hal::WaitForInitialPacket();
Brian Silverman8fce7482020-01-05 13:18:21 -0800631
632 initialized = true;
633 return true;
634}
635
Austin Schuh1e69f942020-11-14 15:06:14 -0800636void HAL_Shutdown(void) {}
637
Austin Schuh812d0d12021-11-04 20:16:48 -0700638void HAL_SimPeriodicBefore(void) {}
639
640void HAL_SimPeriodicAfter(void) {}
641
Brian Silverman8fce7482020-01-05 13:18:21 -0800642int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
643 const char* feature) {
644 if (feature == nullptr) {
645 feature = "";
646 }
647
648 return FRC_NetworkCommunication_nUsageReporting_report(
649 resource, instanceNumber, context, feature);
650}
651
Brian Silverman8fce7482020-01-05 13:18:21 -0800652} // extern "C"