blob: 93e5c15d14ad1ff36017f7e1a09166d869e4a9aa [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>
Brian Silverman8fce7482020-01-05 13:18:21 -080021#include <wpi/mutex.h>
Brian Silverman8fce7482020-01-05 13:18:21 -080022#include <wpi/timestamp.h>
23
24#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080025#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080026#include "hal/ChipObject.h"
27#include "hal/DriverStation.h"
28#include "hal/Errors.h"
29#include "hal/Notifier.h"
30#include "hal/handles/HandlesInternal.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080031#include "visa/visa.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080032
33using namespace hal;
34
35static std::unique_ptr<tGlobal> global;
36static std::unique_ptr<tSysWatchdog> watchdog;
Austin Schuh75263e32022-02-22 18:05:32 -080037static uint64_t dsStartTime;
Brian Silverman8fce7482020-01-05 13:18:21 -080038
39using namespace hal;
40
41namespace hal {
42namespace init {
43void InitializeHAL() {
Austin Schuh812d0d12021-11-04 20:16:48 -070044 InitializeCTREPCM();
45 InitializeREVPH();
Brian Silverman8fce7482020-01-05 13:18:21 -080046 InitializeAddressableLED();
47 InitializeAccelerometer();
48 InitializeAnalogAccumulator();
Austin Schuh1e69f942020-11-14 15:06:14 -080049 InitializeAnalogGyro();
Brian Silverman8fce7482020-01-05 13:18:21 -080050 InitializeAnalogInput();
51 InitializeAnalogInternal();
52 InitializeAnalogOutput();
53 InitializeAnalogTrigger();
54 InitializeCAN();
55 InitializeCANAPI();
Brian Silverman8fce7482020-01-05 13:18:21 -080056 InitializeConstants();
57 InitializeCounter();
58 InitializeDigitalInternal();
59 InitializeDIO();
60 InitializeDMA();
61 InitializeDutyCycle();
62 InitializeEncoder();
63 InitializeFPGAEncoder();
64 InitializeFRCDriverStation();
65 InitializeI2C();
Austin Schuh1e69f942020-11-14 15:06:14 -080066 InitializeInterrupts();
Brian Silverman8fce7482020-01-05 13:18:21 -080067 InitializeMain();
68 InitializeNotifier();
Austin Schuh812d0d12021-11-04 20:16:48 -070069 InitializeCTREPDP();
70 InitializeREVPDH();
Brian Silverman8fce7482020-01-05 13:18:21 -080071 InitializePorts();
72 InitializePower();
73 InitializePWM();
74 InitializeRelay();
Austin Schuh1e69f942020-11-14 15:06:14 -080075 InitializeSerialPort();
Brian Silverman8fce7482020-01-05 13:18:21 -080076 InitializeSPI();
77 InitializeThreads();
78}
79} // namespace init
Austin Schuh1e69f942020-11-14 15:06:14 -080080
81void ReleaseFPGAInterrupt(int32_t interruptNumber) {
82 if (!global) {
83 return;
84 }
85 int32_t status = 0;
86 global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
87 &status);
88 global->strobeInterruptForceOnce(&status);
89}
Austin Schuh75263e32022-02-22 18:05:32 -080090
91uint64_t GetDSInitializeTime() {
92 return dsStartTime;
93}
94
Brian Silverman8fce7482020-01-05 13:18:21 -080095} // namespace hal
96
97extern "C" {
98
99HAL_PortHandle HAL_GetPort(int32_t channel) {
100 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700101 if (channel < 0 || channel >= 255) {
102 return HAL_kInvalidHandle;
103 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800104 return createPortHandle(channel, 1);
105}
106
107HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
108 // Dont allow a number that wouldn't fit in a uint8_t
Austin Schuh812d0d12021-11-04 20:16:48 -0700109 if (channel < 0 || channel >= 255) {
110 return HAL_kInvalidHandle;
111 }
112 if (module < 0 || module >= 255) {
113 return HAL_kInvalidHandle;
114 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800115 return createPortHandle(channel, module);
116}
117
118const char* HAL_GetErrorMessage(int32_t code) {
119 switch (code) {
120 case 0:
121 return "";
Brian Silverman8fce7482020-01-05 13:18:21 -0800122 case NiFpga_Status_FifoTimeout:
123 return NiFpga_Status_FifoTimeout_MESSAGE;
124 case NiFpga_Status_TransferAborted:
125 return NiFpga_Status_TransferAborted_MESSAGE;
126 case NiFpga_Status_MemoryFull:
127 return NiFpga_Status_MemoryFull_MESSAGE;
128 case NiFpga_Status_SoftwareFault:
129 return NiFpga_Status_SoftwareFault_MESSAGE;
130 case NiFpga_Status_InvalidParameter:
131 return NiFpga_Status_InvalidParameter_MESSAGE;
132 case NiFpga_Status_ResourceNotFound:
133 return NiFpga_Status_ResourceNotFound_MESSAGE;
134 case NiFpga_Status_ResourceNotInitialized:
135 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
136 case NiFpga_Status_HardwareFault:
137 return NiFpga_Status_HardwareFault_MESSAGE;
138 case NiFpga_Status_IrqTimeout:
139 return NiFpga_Status_IrqTimeout_MESSAGE;
140 case SAMPLE_RATE_TOO_HIGH:
141 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
142 case VOLTAGE_OUT_OF_RANGE:
143 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
144 case LOOP_TIMING_ERROR:
145 return LOOP_TIMING_ERROR_MESSAGE;
146 case SPI_WRITE_NO_MOSI:
147 return SPI_WRITE_NO_MOSI_MESSAGE;
148 case SPI_READ_NO_MISO:
149 return SPI_READ_NO_MISO_MESSAGE;
150 case SPI_READ_NO_DATA:
151 return SPI_READ_NO_DATA_MESSAGE;
152 case INCOMPATIBLE_STATE:
153 return INCOMPATIBLE_STATE_MESSAGE;
154 case NO_AVAILABLE_RESOURCES:
155 return NO_AVAILABLE_RESOURCES_MESSAGE;
156 case RESOURCE_IS_ALLOCATED:
157 return RESOURCE_IS_ALLOCATED_MESSAGE;
158 case RESOURCE_OUT_OF_RANGE:
159 return RESOURCE_OUT_OF_RANGE_MESSAGE;
160 case HAL_INVALID_ACCUMULATOR_CHANNEL:
161 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
162 case HAL_HANDLE_ERROR:
163 return HAL_HANDLE_ERROR_MESSAGE;
164 case NULL_PARAMETER:
165 return NULL_PARAMETER_MESSAGE;
166 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
167 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
168 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
169 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
170 case PARAMETER_OUT_OF_RANGE:
171 return PARAMETER_OUT_OF_RANGE_MESSAGE;
172 case HAL_COUNTER_NOT_SUPPORTED:
173 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
174 case HAL_ERR_CANSessionMux_InvalidBuffer:
175 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
176 case HAL_ERR_CANSessionMux_MessageNotFound:
177 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
178 case HAL_WARN_CANSessionMux_NoToken:
179 return WARN_CANSessionMux_NoToken_MESSAGE;
180 case HAL_ERR_CANSessionMux_NotAllowed:
181 return ERR_CANSessionMux_NotAllowed_MESSAGE;
182 case HAL_ERR_CANSessionMux_NotInitialized:
183 return ERR_CANSessionMux_NotInitialized_MESSAGE;
Austin Schuh1e69f942020-11-14 15:06:14 -0800184 case VI_ERROR_SYSTEM_ERROR:
185 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
186 case VI_ERROR_INV_OBJECT:
187 return VI_ERROR_INV_OBJECT_MESSAGE;
188 case VI_ERROR_RSRC_LOCKED:
189 return VI_ERROR_RSRC_LOCKED_MESSAGE;
190 case VI_ERROR_RSRC_NFOUND:
191 return VI_ERROR_RSRC_NFOUND_MESSAGE;
192 case VI_ERROR_INV_RSRC_NAME:
193 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
194 case VI_ERROR_QUEUE_OVERFLOW:
195 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
196 case VI_ERROR_IO:
197 return VI_ERROR_IO_MESSAGE;
198 case VI_ERROR_ASRL_PARITY:
199 return VI_ERROR_ASRL_PARITY_MESSAGE;
200 case VI_ERROR_ASRL_FRAMING:
201 return VI_ERROR_ASRL_FRAMING_MESSAGE;
202 case VI_ERROR_ASRL_OVERRUN:
203 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
204 case VI_ERROR_RSRC_BUSY:
205 return VI_ERROR_RSRC_BUSY_MESSAGE;
206 case VI_ERROR_INV_PARAMETER:
207 return VI_ERROR_INV_PARAMETER_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800208 case HAL_PWM_SCALE_ERROR:
209 return HAL_PWM_SCALE_ERROR_MESSAGE;
210 case HAL_SERIAL_PORT_NOT_FOUND:
211 return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
212 case HAL_THREAD_PRIORITY_ERROR:
213 return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
214 case HAL_THREAD_PRIORITY_RANGE_ERROR:
215 return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
216 case HAL_SERIAL_PORT_OPEN_ERROR:
217 return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
218 case HAL_SERIAL_PORT_ERROR:
219 return HAL_SERIAL_PORT_ERROR_MESSAGE;
220 case HAL_CAN_TIMEOUT:
221 return HAL_CAN_TIMEOUT_MESSAGE;
222 case ERR_FRCSystem_NetCommNotResponding:
223 return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
224 case ERR_FRCSystem_NoDSConnection:
225 return ERR_FRCSystem_NoDSConnection_MESSAGE;
226 case HAL_CAN_BUFFER_OVERRUN:
227 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
228 case HAL_LED_CHANNEL_ERROR:
229 return HAL_LED_CHANNEL_ERROR_MESSAGE;
Austin Schuh812d0d12021-11-04 20:16:48 -0700230 case HAL_INVALID_DMA_STATE:
231 return HAL_INVALID_DMA_STATE_MESSAGE;
232 case HAL_INVALID_DMA_ADDITION:
233 return HAL_INVALID_DMA_ADDITION_MESSAGE;
234 case HAL_USE_LAST_ERROR:
235 return HAL_USE_LAST_ERROR_MESSAGE;
236 case HAL_CONSOLE_OUT_ENABLED_ERROR:
237 return HAL_CONSOLE_OUT_ENABLED_ERROR_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800238 default:
239 return "Unknown error status";
240 }
241}
242
Austin Schuh812d0d12021-11-04 20:16:48 -0700243HAL_RuntimeType HAL_GetRuntimeType(void) {
244 nLoadOut::tTargetClass targetClass = nLoadOut::getTargetClass();
245 if (targetClass == nLoadOut::kTargetClass_RoboRIO2) {
246 return HAL_Runtime_RoboRIO2;
247 }
248 return HAL_Runtime_RoboRIO;
249}
Brian Silverman8fce7482020-01-05 13:18:21 -0800250
251int32_t HAL_GetFPGAVersion(int32_t* status) {
252 if (!global) {
253 *status = NiFpga_Status_ResourceNotInitialized;
254 return 0;
255 }
256 return global->readVersion(status);
257}
258
259int64_t HAL_GetFPGARevision(int32_t* status) {
260 if (!global) {
261 *status = NiFpga_Status_ResourceNotInitialized;
262 return 0;
263 }
264 return global->readRevision(status);
265}
266
267uint64_t HAL_GetFPGATime(int32_t* status) {
268 if (!global) {
269 *status = NiFpga_Status_ResourceNotInitialized;
270 return 0;
271 }
272 *status = 0;
273 uint64_t upper1 = global->readLocalTimeUpper(status);
274 uint32_t lower = global->readLocalTime(status);
275 uint64_t upper2 = global->readLocalTimeUpper(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700276 if (*status != 0) {
277 return 0;
278 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800279 if (upper1 != upper2) {
280 // Rolled over between the lower call, reread lower
281 lower = global->readLocalTime(status);
Austin Schuh812d0d12021-11-04 20:16:48 -0700282 if (*status != 0) {
283 return 0;
284 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800285 }
286 return (upper2 << 32) + lower;
287}
288
Austin Schuh812d0d12021-11-04 20:16:48 -0700289uint64_t HAL_ExpandFPGATime(uint32_t unexpandedLower, int32_t* status) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800290 // Capture the current FPGA time. This will give us the upper half of the
291 // clock.
Austin Schuh812d0d12021-11-04 20:16:48 -0700292 uint64_t fpgaTime = HAL_GetFPGATime(status);
293 if (*status != 0) {
294 return 0;
295 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800296
297 // Now, we need to detect the case where the lower bits rolled over after we
298 // sampled. In that case, the upper bits will be 1 bigger than they should
299 // be.
300
301 // Break it into lower and upper portions.
Austin Schuh812d0d12021-11-04 20:16:48 -0700302 uint32_t lower = fpgaTime & 0xffffffffull;
303 uint64_t upper = (fpgaTime >> 32) & 0xffffffff;
Brian Silverman8fce7482020-01-05 13:18:21 -0800304
305 // The time was sampled *before* the current time, so roll it back.
Austin Schuh812d0d12021-11-04 20:16:48 -0700306 if (lower < unexpandedLower) {
Brian Silverman8fce7482020-01-05 13:18:21 -0800307 --upper;
308 }
309
Austin Schuh812d0d12021-11-04 20:16:48 -0700310 return (upper << 32) + static_cast<uint64_t>(unexpandedLower);
Brian Silverman8fce7482020-01-05 13:18:21 -0800311}
312
313HAL_Bool HAL_GetFPGAButton(int32_t* status) {
314 if (!global) {
315 *status = NiFpga_Status_ResourceNotInitialized;
316 return false;
317 }
318 return global->readUserButton(status);
319}
320
321HAL_Bool HAL_GetSystemActive(int32_t* status) {
322 if (!watchdog) {
323 *status = NiFpga_Status_ResourceNotInitialized;
324 return false;
325 }
326 return watchdog->readStatus_SystemActive(status);
327}
328
329HAL_Bool HAL_GetBrownedOut(int32_t* status) {
330 if (!watchdog) {
331 *status = NiFpga_Status_ResourceNotInitialized;
332 return false;
333 }
334 return !(watchdog->readStatus_PowerAlive(status));
335}
336
337static bool killExistingProgram(int timeout, int mode) {
338 // Kill any previous robot programs
339 std::fstream fs;
340 // By making this both in/out, it won't give us an error if it doesnt exist
341 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
Austin Schuh812d0d12021-11-04 20:16:48 -0700342 if (fs.bad()) {
343 return false;
344 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800345
346 pid_t pid = 0;
347 if (!fs.eof() && !fs.fail()) {
348 fs >> pid;
349 // see if the pid is around, but we don't want to mess with init id=1, or
350 // ourselves
351 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700352 std::puts("Killing previously running FRC program...");
Brian Silverman8fce7482020-01-05 13:18:21 -0800353 kill(pid, SIGTERM); // try to kill it
354 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
355 if (kill(pid, 0) == 0) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800356 // still not successful
Austin Schuh812d0d12021-11-04 20:16:48 -0700357 fmt::print(
358 "FRC pid {} did not die within {} ms. Force killing with kill -9\n",
359 pid, timeout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800360 // Force kill -9
361 auto forceKill = kill(pid, SIGKILL);
362 if (forceKill != 0) {
363 auto errorMsg = std::strerror(forceKill);
Austin Schuh812d0d12021-11-04 20:16:48 -0700364 fmt::print("Kill -9 error: {}\n", errorMsg);
Brian Silverman8fce7482020-01-05 13:18:21 -0800365 }
366 // Give a bit of time for the kill to take place
367 std::this_thread::sleep_for(std::chrono::milliseconds(250));
368 }
369 }
370 }
371 fs.close();
372 // we will re-open it write only to truncate the file
373 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
374 fs.seekp(0);
375 pid = getpid();
376 fs << pid << std::endl;
377 fs.close();
378 return true;
379}
380
381HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
382 static std::atomic_bool initialized{false};
383 static wpi::mutex initializeMutex;
384 // Initial check, as if it's true initialization has finished
Austin Schuh812d0d12021-11-04 20:16:48 -0700385 if (initialized) {
386 return true;
387 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800388
389 std::scoped_lock lock(initializeMutex);
390 // Second check in case another thread was waiting
Austin Schuh812d0d12021-11-04 20:16:48 -0700391 if (initialized) {
392 return true;
393 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800394
395 hal::init::InitializeHAL();
396
397 hal::init::HAL_IsInitialized.store(true);
398
399 setlinebuf(stdin);
400 setlinebuf(stdout);
Brian Silverman8fce7482020-01-05 13:18:21 -0800401
402 prctl(PR_SET_PDEATHSIG, SIGTERM);
403
404 // Return false if program failed to kill an existing program
405 if (!killExistingProgram(timeout, mode)) {
406 return false;
407 }
408
409 FRC_NetworkCommunication_Reserve(nullptr);
410
411 std::atexit([]() {
412 // Unregister our new data condition variable.
413 setNewDataSem(nullptr);
414 });
415
Brian Silverman8fce7482020-01-05 13:18:21 -0800416 nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
Austin Schuh1e69f942020-11-14 15:06:14 -0800417 nLoadOut::getTargetClass();
Brian Silverman8fce7482020-01-05 13:18:21 -0800418
419 int32_t status = 0;
420 global.reset(tGlobal::create(&status));
421 watchdog.reset(tSysWatchdog::create(&status));
422
Austin Schuh812d0d12021-11-04 20:16:48 -0700423 if (status != 0) {
424 return false;
425 }
Brian Silverman8fce7482020-01-05 13:18:21 -0800426
427 HAL_InitializeDriverStation();
428
Austin Schuh75263e32022-02-22 18:05:32 -0800429 dsStartTime = HAL_GetFPGATime(&status);
430 if (status != 0) {
431 return false;
432 }
433
Brian Silverman8fce7482020-01-05 13:18:21 -0800434 // Set WPI_Now to use FPGA timestamp
435 wpi::SetNowImpl([]() -> uint64_t {
436 int32_t status = 0;
437 uint64_t rv = HAL_GetFPGATime(&status);
438 if (status != 0) {
Austin Schuh812d0d12021-11-04 20:16:48 -0700439 fmt::print(stderr,
440 "Call to HAL_GetFPGATime failed in wpi::Now() with status {}. "
441 "Initialization might have failed. Time will not be correct\n",
442 status);
443 std::fflush(stderr);
Brian Silverman8fce7482020-01-05 13:18:21 -0800444 return 0u;
445 }
446 return rv;
447 });
448
449 initialized = true;
450 return true;
451}
452
Austin Schuh1e69f942020-11-14 15:06:14 -0800453void HAL_Shutdown(void) {}
454
Austin Schuh812d0d12021-11-04 20:16:48 -0700455void HAL_SimPeriodicBefore(void) {}
456
457void HAL_SimPeriodicAfter(void) {}
458
Brian Silverman8fce7482020-01-05 13:18:21 -0800459int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
460 const char* feature) {
461 if (feature == nullptr) {
462 feature = "";
463 }
464
465 return FRC_NetworkCommunication_nUsageReporting_report(
466 resource, instanceNumber, context, feature);
467}
468
Brian Silverman8fce7482020-01-05 13:18:21 -0800469} // extern "C"