blob: d00bf9f370af0a85488f77f0d1a20cfb2858d7b4 [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 Kuszmaulb13e13f2023-11-22 20:44:04 -080036#include "hal/roborio/HMB.h"
James Kuszmaulcf324122023-01-14 14:07:17 -080037#include "hal/roborio/InterruptManager.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080038#include "visa/visa.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080039
40using namespace hal;
41
42static std::unique_ptr<tGlobal> global;
43static std::unique_ptr<tSysWatchdog> watchdog;
Austin Schuh75263e32022-02-22 18:05:32 -080044static uint64_t dsStartTime;
Brian Silverman8fce7482020-01-05 13:18:21 -080045
James Kuszmaulcf324122023-01-14 14:07:17 -080046static char roboRioCommentsString[64];
47static size_t roboRioCommentsStringSize;
48static bool roboRioCommentsStringInitialized;
49
James Kuszmaulb13e13f2023-11-22 20:44:04 -080050static int32_t teamNumber = -1;
51
52static const volatile HAL_HMBData* hmbBuffer;
53#define HAL_HMB_TIMESTAMP_OFFSET 5
54
Brian Silverman8fce7482020-01-05 13:18:21 -080055using namespace hal;
56
57namespace hal {
James Kuszmaulcf324122023-01-14 14:07:17 -080058void InitializeDriverStation();
James Kuszmaulb13e13f2023-11-22 20:44:04 -080059void WaitForInitialPacket();
Brian Silverman8fce7482020-01-05 13:18:21 -080060namespace init {
61void InitializeHAL() {
Austin Schuh812d0d12021-11-04 20:16:48 -070062 InitializeCTREPCM();
63 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -080064 InitializeAddressableLED();
65 InitializeAccelerometer();
66 InitializeAnalogAccumulator();
Austin Schuh1e69f942020-11-14 15:06:14 -080067 InitializeAnalogGyro();
Brian Silverman8fce7482020-01-05 13:18:21 -080068 InitializeAnalogInput();
69 InitializeAnalogInternal();
70 InitializeAnalogOutput();
71 InitializeAnalogTrigger();
72 InitializeCAN();
73 InitializeCANAPI();
Brian Silverman8fce7482020-01-05 13:18:21 -080074 InitializeConstants();
75 InitializeCounter();
76 InitializeDigitalInternal();
77 InitializeDIO();
78 InitializeDMA();
79 InitializeDutyCycle();
80 InitializeEncoder();
81 InitializeFPGAEncoder();
82 InitializeFRCDriverStation();
83 InitializeI2C();
Austin Schuh1e69f942020-11-14 15:06:14 -080084 InitializeInterrupts();
Brian Silverman8fce7482020-01-05 13:18:21 -080085 InitializeMain();
86 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -070087 InitializeCTREPDP();
88 InitializeREVPDH();
Brian Silverman8fce7482020-01-05 13:18:21 -080089 InitializePorts();
90 InitializePower();
91 InitializePWM();
92 InitializeRelay();
Austin Schuh1e69f942020-11-14 15:06:14 -080093 InitializeSerialPort();
Brian Silverman8fce7482020-01-05 13:18:21 -080094 InitializeSPI();
95 InitializeThreads();
96}
97} // namespace init
Austin Schuh1e69f942020-11-14 15:06:14 -080098
99void ReleaseFPGAInterrupt(int32_t interruptNumber) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800100 hal::init::CheckInit();
Austin Schuh1e69f942020-11-14 15:06:14 -0800101 if (!global) {
102 return;
103 }
104 int32_t status = 0;
105 global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
106 &status);
107 global->strobeInterruptForceOnce(&status);
108}
Austin Schuh75263e32022-02-22 18:05:32 -0800109
110uint64_t GetDSInitializeTime() {
111 return dsStartTime;
112}
113
Brian Silverman8fce7482020-01-05 13:18:21 -0800114} // namespace hal
115
116extern "C" {
117
118HAL_PortHandle HAL_GetPort(int32_t channel) {
119 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700120 if (channel < 0 || channel >= 255) {
121 return HAL_kInvalidHandle;
122 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800123 return createPortHandle(channel, 1);
124}
125
126HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
127 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700128 if (channel < 0 || channel >= 255) {
129 return HAL_kInvalidHandle;
130 }
131 if (module < 0 || module >= 255) {
132 return HAL_kInvalidHandle;
133 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800134 return createPortHandle(channel, module);
135}
136
137const char* HAL_GetErrorMessage(int32_t code) {
138 switch (code) {
139 case 0:
140 return "";
Brian Silverman8fce7482020-01-05 13:18:21 -0800141 case NiFpga_Status_FifoTimeout:
142 return NiFpga_Status_FifoTimeout_MESSAGE;
143 case NiFpga_Status_TransferAborted:
144 return NiFpga_Status_TransferAborted_MESSAGE;
145 case NiFpga_Status_MemoryFull:
146 return NiFpga_Status_MemoryFull_MESSAGE;
147 case NiFpga_Status_SoftwareFault:
148 return NiFpga_Status_SoftwareFault_MESSAGE;
149 case NiFpga_Status_InvalidParameter:
150 return NiFpga_Status_InvalidParameter_MESSAGE;
151 case NiFpga_Status_ResourceNotFound:
152 return NiFpga_Status_ResourceNotFound_MESSAGE;
153 case NiFpga_Status_ResourceNotInitialized:
154 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
155 case NiFpga_Status_HardwareFault:
156 return NiFpga_Status_HardwareFault_MESSAGE;
157 case NiFpga_Status_IrqTimeout:
158 return NiFpga_Status_IrqTimeout_MESSAGE;
159 case SAMPLE_RATE_TOO_HIGH:
160 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
161 case VOLTAGE_OUT_OF_RANGE:
162 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
163 case LOOP_TIMING_ERROR:
164 return LOOP_TIMING_ERROR_MESSAGE;
165 case SPI_WRITE_NO_MOSI:
166 return SPI_WRITE_NO_MOSI_MESSAGE;
167 case SPI_READ_NO_MISO:
168 return SPI_READ_NO_MISO_MESSAGE;
169 case SPI_READ_NO_DATA:
170 return SPI_READ_NO_DATA_MESSAGE;
171 case INCOMPATIBLE_STATE:
172 return INCOMPATIBLE_STATE_MESSAGE;
173 case NO_AVAILABLE_RESOURCES:
174 return NO_AVAILABLE_RESOURCES_MESSAGE;
175 case RESOURCE_IS_ALLOCATED:
176 return RESOURCE_IS_ALLOCATED_MESSAGE;
177 case RESOURCE_OUT_OF_RANGE:
178 return RESOURCE_OUT_OF_RANGE_MESSAGE;
179 case HAL_INVALID_ACCUMULATOR_CHANNEL:
180 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
181 case HAL_HANDLE_ERROR:
182 return HAL_HANDLE_ERROR_MESSAGE;
183 case NULL_PARAMETER:
184 return NULL_PARAMETER_MESSAGE;
185 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
186 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
187 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
188 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
189 case PARAMETER_OUT_OF_RANGE:
190 return PARAMETER_OUT_OF_RANGE_MESSAGE;
191 case HAL_COUNTER_NOT_SUPPORTED:
192 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
193 case HAL_ERR_CANSessionMux_InvalidBuffer:
194 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
195 case HAL_ERR_CANSessionMux_MessageNotFound:
196 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
197 case HAL_WARN_CANSessionMux_NoToken:
198 return WARN_CANSessionMux_NoToken_MESSAGE;
199 case HAL_ERR_CANSessionMux_NotAllowed:
200 return ERR_CANSessionMux_NotAllowed_MESSAGE;
201 case HAL_ERR_CANSessionMux_NotInitialized:
202 return ERR_CANSessionMux_NotInitialized_MESSAGE;
Austin Schuh1e69f942020-11-14 15:06:14 -0800203 case VI_ERROR_SYSTEM_ERROR:
204 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
205 case VI_ERROR_INV_OBJECT:
206 return VI_ERROR_INV_OBJECT_MESSAGE;
207 case VI_ERROR_RSRC_LOCKED:
208 return VI_ERROR_RSRC_LOCKED_MESSAGE;
209 case VI_ERROR_RSRC_NFOUND:
210 return VI_ERROR_RSRC_NFOUND_MESSAGE;
211 case VI_ERROR_INV_RSRC_NAME:
212 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
213 case VI_ERROR_QUEUE_OVERFLOW:
214 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
215 case VI_ERROR_IO:
216 return VI_ERROR_IO_MESSAGE;
217 case VI_ERROR_ASRL_PARITY:
218 return VI_ERROR_ASRL_PARITY_MESSAGE;
219 case VI_ERROR_ASRL_FRAMING:
220 return VI_ERROR_ASRL_FRAMING_MESSAGE;
221 case VI_ERROR_ASRL_OVERRUN:
222 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
223 case VI_ERROR_RSRC_BUSY:
224 return VI_ERROR_RSRC_BUSY_MESSAGE;
225 case VI_ERROR_INV_PARAMETER:
226 return VI_ERROR_INV_PARAMETER_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800227 case HAL_PWM_SCALE_ERROR:
228 return HAL_PWM_SCALE_ERROR_MESSAGE;
229 case HAL_SERIAL_PORT_NOT_FOUND:
230 return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
231 case HAL_THREAD_PRIORITY_ERROR:
232 return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
233 case HAL_THREAD_PRIORITY_RANGE_ERROR:
234 return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
235 case HAL_SERIAL_PORT_OPEN_ERROR:
236 return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
237 case HAL_SERIAL_PORT_ERROR:
238 return HAL_SERIAL_PORT_ERROR_MESSAGE;
239 case HAL_CAN_TIMEOUT:
240 return HAL_CAN_TIMEOUT_MESSAGE;
241 case ERR_FRCSystem_NetCommNotResponding:
242 return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
243 case ERR_FRCSystem_NoDSConnection:
244 return ERR_FRCSystem_NoDSConnection_MESSAGE;
245 case HAL_CAN_BUFFER_OVERRUN:
246 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
247 case HAL_LED_CHANNEL_ERROR:
248 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700249 case HAL_INVALID_DMA_STATE:
250 return HAL_INVALID_DMA_STATE_MESSAGE;
251 case HAL_INVALID_DMA_ADDITION:
252 return HAL_INVALID_DMA_ADDITION_MESSAGE;
253 case HAL_USE_LAST_ERROR:
254 return HAL_USE_LAST_ERROR_MESSAGE;
255 case HAL_CONSOLE_OUT_ENABLED_ERROR:
256 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800257 default:
258 return "Unknown error status";
259 }
260}
261
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800262static HAL_RuntimeType runtimeType = HAL_Runtime_RoboRIO;
263
Austin Schuh812d0d12021-11-04 20:16:48 -0700264HAL_RuntimeType HAL_GetRuntimeType(void) {
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800265 return runtimeType;
Austin Schuh812d0d12021-11-04 20:16:48 -0700266}
Brian Silverman8fce7482020-01-05 13:18:21 -0800267
268int32_t HAL_GetFPGAVersion(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800269 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800270 if (!global) {
271 *status = NiFpga_Status_ResourceNotInitialized;
272 return 0;
273 }
274 return global->readVersion(status);
275}
276
277int64_t HAL_GetFPGARevision(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800278 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800279 if (!global) {
280 *status = NiFpga_Status_ResourceNotInitialized;
281 return 0;
282 }
283 return global->readRevision(status);
284}
285
James Kuszmaulcf324122023-01-14 14:07:17 -0800286size_t HAL_GetSerialNumber(char* buffer, size_t size) {
287 const char* serialNum = std::getenv("serialnum");
288 if (serialNum) {
289 std::strncpy(buffer, serialNum, size);
290 buffer[size - 1] = '\0';
291 return std::strlen(buffer);
292 } else {
293 if (size > 0) {
294 buffer[0] = '\0';
295 }
296 return 0;
297 }
298}
299
300void InitializeRoboRioComments(void) {
301 if (!roboRioCommentsStringInitialized) {
302 std::error_code ec;
303 std::unique_ptr<wpi::MemoryBuffer> fileBuffer =
304 wpi::MemoryBuffer::GetFile("/etc/machine-info", ec);
305
306 std::string_view fileContents;
307 if (fileBuffer && !ec) {
308 fileContents =
309 std::string_view(reinterpret_cast<const char*>(fileBuffer->begin()),
310 fileBuffer->size());
311 } else {
312 roboRioCommentsStringSize = 0;
313 roboRioCommentsStringInitialized = true;
314 return;
315 }
316 std::string_view searchString = "PRETTY_HOSTNAME=\"";
317
318 size_t start = fileContents.find(searchString);
319 if (start == std::string_view::npos) {
320 roboRioCommentsStringSize = 0;
321 roboRioCommentsStringInitialized = true;
322 return;
323 }
324 start += searchString.size();
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800325 std::string_view escapedComments =
326 wpi::slice(fileContents, start, fileContents.size());
James Kuszmaulcf324122023-01-14 14:07:17 -0800327 wpi::SmallString<64> buf;
328 auto [unescapedComments, rem] = wpi::UnescapeCString(escapedComments, buf);
329 unescapedComments.copy(roboRioCommentsString,
330 sizeof(roboRioCommentsString));
331
332 if (unescapedComments.size() > sizeof(roboRioCommentsString)) {
333 roboRioCommentsStringSize = sizeof(roboRioCommentsString);
334 } else {
335 roboRioCommentsStringSize = unescapedComments.size();
336 }
337 roboRioCommentsStringInitialized = true;
338 }
339}
340
341size_t HAL_GetComments(char* buffer, size_t size) {
342 if (!roboRioCommentsStringInitialized) {
343 InitializeRoboRioComments();
344 }
345 size_t toCopy = size;
346 if (size > roboRioCommentsStringSize) {
347 toCopy = roboRioCommentsStringSize;
348 }
349 std::memcpy(buffer, roboRioCommentsString, toCopy);
350 if (toCopy < size) {
351 buffer[toCopy] = '\0';
352 } else {
353 buffer[toCopy - 1] = '\0';
354 }
355 return toCopy;
356}
357
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800358void InitializeTeamNumber(void) {
359 char hostnameBuf[25];
360 auto status = gethostname(hostnameBuf, sizeof(hostnameBuf));
361 if (status != 0) {
362 teamNumber = 0;
363 return;
364 }
365
366 std::string_view hostname{hostnameBuf, sizeof(hostnameBuf)};
367
368 // hostname is frc-{TEAM}-roborio
369 // Split string around '-' (max of 2 splits), take the second element of the
370 // resulting array.
371 wpi::SmallVector<std::string_view> elements;
372 wpi::split(hostname, elements, "-", 2);
373 if (elements.size() < 3) {
374 teamNumber = 0;
375 return;
376 }
377
378 teamNumber = wpi::parse_integer<int32_t>(elements[1], 10).value_or(0);
379}
380
381int32_t HAL_GetTeamNumber(void) {
382 if (teamNumber == -1) {
383 InitializeTeamNumber();
384 }
385 return teamNumber;
386}
387
Brian Silverman8fce7482020-01-05 13:18:21 -0800388uint64_t HAL_GetFPGATime(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800389 hal::init::CheckInit();
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800390 if (!hmbBuffer) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800391 *status = NiFpga_Status_ResourceNotInitialized;
392 return 0;
393 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800394
395 asm("dmb");
396 uint64_t upper1 = hmbBuffer->Timestamp.Upper;
397 asm("dmb");
398 uint32_t lower = hmbBuffer->Timestamp.Lower;
399 asm("dmb");
400 uint64_t upper2 = hmbBuffer->Timestamp.Upper;
401
Brian Silverman8fce7482020-01-05 13:18:21 -0800402 if (upper1 != upper2) {
403 // Rolled over between the lower call, reread lower
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800404 asm("dmb");
405 lower = hmbBuffer->Timestamp.Lower;
Brian Silverman8fce7482020-01-05 13:18:21 -0800406 }
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800407 // 5 is added here because the time to write from the FPGA
408 // to the HMB buffer is longer then the time to read
409 // from the time register. This would cause register based
410 // timestamps to be ahead of HMB timestamps, which could
411 // be very bad.
412 return (upper2 << 32) + lower + HAL_HMB_TIMESTAMP_OFFSET;
Brian Silverman8fce7482020-01-05 13:18:21 -0800413}
414
Austin Schuh812d0d12021-11-04 20:16:48 -0700415uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800416 // Capture the current FPGA time. This will give us the upper half of the
417 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700418 uint64_t fpgaTime = HAL_GetFPGATime(status);
419 if (*status != 0) {
420 return 0;
421 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800422
423 // Now, we need to detect the case where the lower bits rolled over after we
424 // sampled. In that case, the upper bits will be 1 bigger than they should
425 // be.
426
427 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700428 uint32_t lower = fpgaTime & 0xffffffffull;
429 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800430
431 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700432 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800433 --upper;
434 }
435
Austin Schuh812d0d12021-11-04 20:16:48 -0700436 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800437}
438
439HAL_Bool HAL_GetFPGAButton(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800440 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800441 if (!global) {
442 *status = NiFpga_Status_ResourceNotInitialized;
443 return false;
444 }
445 return global->readUserButton(status);
446}
447
448HAL_Bool HAL_GetSystemActive(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800449 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800450 if (!watchdog) {
451 *status = NiFpga_Status_ResourceNotInitialized;
452 return false;
453 }
454 return watchdog->readStatus_SystemActive(status);
455}
456
457HAL_Bool HAL_GetBrownedOut(int32_t* status) {
James Kuszmaulcf324122023-01-14 14:07:17 -0800458 hal::init::CheckInit();
Brian Silverman8fce7482020-01-05 13:18:21 -0800459 if (!watchdog) {
460 *status = NiFpga_Status_ResourceNotInitialized;
461 return false;
462 }
463 return !(watchdog->readStatus_PowerAlive(status));
464}
465
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800466HAL_Bool HAL_GetRSLState(int32_t* status) {
467 hal::init::CheckInit();
468 if (!global) {
469 *status = NiFpga_Status_ResourceNotInitialized;
470 return false;
471 }
472 return global->readLEDs_RSL(status);
473}
474
475HAL_Bool HAL_GetSystemTimeValid(int32_t* status) {
476 uint8_t timeWasSet = 0;
477 *status = FRC_NetworkCommunication_getTimeWasSet(&timeWasSet);
478 return timeWasSet != 0;
479}
480
Brian Silverman8fce7482020-01-05 13:18:21 -0800481static bool killExistingProgram(int timeout, int mode) {
482 // Kill any previous robot programs
483 std::fstream fs;
484 // By making this both in/out, it won't give us an error if it doesnt exist
485 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
Austin Schuh812d0d12021-11-04 20:16:48 -0700486 if (fs.bad()) {
487 return false;
488 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800489
490 pid_t pid = 0;
491 if (!fs.eof() && !fs.fail()) {
492 fs >> pid;
493 // see if the pid is around, but we don't want to mess with init id=1, or
494 // ourselves
495 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700496 std::puts("Killing previously running FRC program...");
Brian Silverman8fce7482020-01-05 13:18:21 -0800497 kill(pid, SIGTERM); // try to kill it
498 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
499 if (kill(pid, 0) == 0) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800500 // still not successful
Austin Schuh812d0d12021-11-04 20:16:48 -0700501 fmt::print(
502 "FRC pid {} did not die within {} ms. Force killing with kill -9\n",
503 pid, timeout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800504 // Force kill -9
505 auto forceKill = kill(pid, SIGKILL);
506 if (forceKill != 0) {
507 auto errorMsg = std::strerror(forceKill);
Austin Schuh812d0d12021-11-04 20:16:48 -0700508 fmt::print("Kill -9 error: {}\n", errorMsg);
Brian Silverman8fce7482020-01-05 13:18:21 -0800509 }
510 // Give a bit of time for the kill to take place
511 std::this_thread::sleep_for(std::chrono::milliseconds(250));
512 }
513 }
514 }
515 fs.close();
516 // we will re-open it write only to truncate the file
517 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
518 fs.seekp(0);
519 pid = getpid();
520 fs << pid << std::endl;
521 fs.close();
522 return true;
523}
524
525HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
526 static std::atomic_bool initialized{false};
527 static wpi::mutex initializeMutex;
528 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700529 if (initialized) {
530 return true;
531 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800532
533 std::scoped_lock lock(initializeMutex);
534 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700535 if (initialized) {
536 return true;
537 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800538
James Kuszmaulcf324122023-01-14 14:07:17 -0800539 int fpgaInit = hal::init::InitializeFPGA();
540 if (fpgaInit != HAL_SUCCESS) {
541 return false;
542 }
543
Brian Silverman8fce7482020-01-05 13:18:21 -0800544 hal::init::InitializeHAL();
545
546 hal::init::HAL_IsInitialized.store(true);
547
548 setlinebuf(stdin);
549 setlinebuf(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800550
551 prctl(PR_SET_PDEATHSIG, SIGTERM);
552
553 // Return false if program failed to kill an existing program
554 if (!killExistingProgram(timeout, mode)) {
555 return false;
556 }
557
558 FRC_NetworkCommunication_Reserve(nullptr);
559
560 std::atexit([]() {
561 // Unregister our new data condition variable.
562 setNewDataSem(nullptr);
563 });
564
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800565 // Setup WPI_Now to use FPGA timestamp
566 // this also sets nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass
567 wpi::impl::SetupNowRio();
Brian Silverman8fce7482020-01-05 13:18:21 -0800568
569 int32_t status = 0;
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800570
571 HAL_InitializeHMB(&status);
572 if (status != 0) {
573 return false;
574 }
575 hmbBuffer = HAL_GetHMBBuffer();
576
Brian Silverman8fce7482020-01-05 13:18:21 -0800577 global.reset(tGlobal::create(&status));
578 watchdog.reset(tSysWatchdog::create(&status));
579
Austin Schuh812d0d12021-11-04 20:16:48 -0700580 if (status != 0) {
581 return false;
582 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800583
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800584 nLoadOut::tTargetClass targetClass = nLoadOut::getTargetClass();
585 if (targetClass == nLoadOut::kTargetClass_RoboRIO2) {
586 runtimeType = HAL_Runtime_RoboRIO2;
587 } else {
588 runtimeType = HAL_Runtime_RoboRIO;
589 }
590
James Kuszmaulcf324122023-01-14 14:07:17 -0800591 InterruptManager::Initialize(global->getSystemInterface());
592
593 hal::InitializeDriverStation();
Brian Silverman8fce7482020-01-05 13:18:21 -0800594
Austin Schuh75263e32022-02-22 18:05:32 -0800595 dsStartTime = HAL_GetFPGATime(&status);
596 if (status != 0) {
597 return false;
598 }
599
James Kuszmaulb13e13f2023-11-22 20:44:04 -0800600 hal::WaitForInitialPacket();
Brian Silverman8fce7482020-01-05 13:18:21 -0800601
602 initialized = true;
603 return true;
604}
605
Austin Schuh1e69f942020-11-14 15:06:14 -0800606void HAL_Shutdown(void) {}
607
Austin Schuh812d0d12021-11-04 20:16:48 -0700608void HAL_SimPeriodicBefore(void) {}
609
610void HAL_SimPeriodicAfter(void) {}
611
Brian Silverman8fce7482020-01-05 13:18:21 -0800612int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
613 const char* feature) {
614 if (feature == nullptr) {
615 feature = "";
616 }
617
618 return FRC_NetworkCommunication_nUsageReporting_report(
619 resource, instanceNumber, context, feature);
620}
621
Brian Silverman8fce7482020-01-05 13:18:21 -0800622} // extern "C"