blob: 17ef0b9cb242e96fb5879d5390b7893103e2a7a7 [file] [log] [blame]
Brian Silverman8fce7482020-01-05 13:18:21 -08001/*----------------------------------------------------------------------------*/
Austin Schuh1e69f942020-11-14 15:06:14 -08002/* Copyright (c) 2016-2020 FIRST. All Rights Reserved. */
Brian Silverman8fce7482020-01-05 13:18:21 -08003/* Open Source Software - may be modified and shared by FRC teams. The code */
4/* must be accompanied by the FIRST BSD license file in the root directory of */
5/* the project. */
6/*----------------------------------------------------------------------------*/
7
8#include "hal/HAL.h"
9
10#include <signal.h> // linux for kill
11#include <sys/prctl.h>
12#include <unistd.h>
13
14#include <atomic>
15#include <cstdlib>
16#include <fstream>
17#include <thread>
18
19#include <FRC_NetworkCommunication/FRCComm.h>
20#include <FRC_NetworkCommunication/LoadOut.h>
21#include <FRC_NetworkCommunication/UsageReporting.h>
22#include <wpi/mutex.h>
23#include <wpi/raw_ostream.h>
24#include <wpi/timestamp.h>
25
26#include "HALInitializer.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080027#include "HALInternal.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080028#include "ctre/ctre.h"
29#include "hal/ChipObject.h"
30#include "hal/DriverStation.h"
31#include "hal/Errors.h"
32#include "hal/Notifier.h"
33#include "hal/handles/HandlesInternal.h"
Austin Schuh1e69f942020-11-14 15:06:14 -080034#include "visa/visa.h"
Brian Silverman8fce7482020-01-05 13:18:21 -080035
36using namespace hal;
37
38static std::unique_ptr<tGlobal> global;
39static std::unique_ptr<tSysWatchdog> watchdog;
40
41using namespace hal;
42
43namespace hal {
44namespace init {
45void InitializeHAL() {
46 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();
56 InitializeCompressor();
57 InitializeConstants();
58 InitializeCounter();
59 InitializeDigitalInternal();
60 InitializeDIO();
61 InitializeDMA();
62 InitializeDutyCycle();
63 InitializeEncoder();
64 InitializeFPGAEncoder();
65 InitializeFRCDriverStation();
66 InitializeI2C();
Austin Schuh1e69f942020-11-14 15:06:14 -080067 InitializeInterrupts();
Brian Silverman8fce7482020-01-05 13:18:21 -080068 InitializeMain();
69 InitializeNotifier();
70 InitializePCMInternal();
71 InitializePDP();
72 InitializePorts();
73 InitializePower();
74 InitializePWM();
75 InitializeRelay();
Austin Schuh1e69f942020-11-14 15:06:14 -080076 InitializeSerialPort();
Brian Silverman8fce7482020-01-05 13:18:21 -080077 InitializeSolenoid();
78 InitializeSPI();
79 InitializeThreads();
80}
81} // namespace init
Austin Schuh1e69f942020-11-14 15:06:14 -080082
83void ReleaseFPGAInterrupt(int32_t interruptNumber) {
84 if (!global) {
85 return;
86 }
87 int32_t status = 0;
88 global->writeInterruptForceNumber(static_cast<unsigned char>(interruptNumber),
89 &status);
90 global->strobeInterruptForceOnce(&status);
91}
Brian Silverman8fce7482020-01-05 13:18:21 -080092} // namespace hal
93
94extern "C" {
95
96HAL_PortHandle HAL_GetPort(int32_t channel) {
97 // Dont allow a number that wouldn't fit in a uint8_t
98 if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
99 return createPortHandle(channel, 1);
100}
101
102HAL_PortHandle HAL_GetPortWithModule(int32_t module, int32_t channel) {
103 // Dont allow a number that wouldn't fit in a uint8_t
104 if (channel < 0 || channel >= 255) return HAL_kInvalidHandle;
105 if (module < 0 || module >= 255) return HAL_kInvalidHandle;
106 return createPortHandle(channel, module);
107}
108
109const char* HAL_GetErrorMessage(int32_t code) {
110 switch (code) {
111 case 0:
112 return "";
113 case CTR_RxTimeout:
114 return CTR_RxTimeout_MESSAGE;
115 case CTR_TxTimeout:
116 return CTR_TxTimeout_MESSAGE;
117 case CTR_InvalidParamValue:
118 return CTR_InvalidParamValue_MESSAGE;
119 case CTR_UnexpectedArbId:
120 return CTR_UnexpectedArbId_MESSAGE;
121 case CTR_TxFailed:
122 return CTR_TxFailed_MESSAGE;
123 case CTR_SigNotUpdated:
124 return CTR_SigNotUpdated_MESSAGE;
125 case NiFpga_Status_FifoTimeout:
126 return NiFpga_Status_FifoTimeout_MESSAGE;
127 case NiFpga_Status_TransferAborted:
128 return NiFpga_Status_TransferAborted_MESSAGE;
129 case NiFpga_Status_MemoryFull:
130 return NiFpga_Status_MemoryFull_MESSAGE;
131 case NiFpga_Status_SoftwareFault:
132 return NiFpga_Status_SoftwareFault_MESSAGE;
133 case NiFpga_Status_InvalidParameter:
134 return NiFpga_Status_InvalidParameter_MESSAGE;
135 case NiFpga_Status_ResourceNotFound:
136 return NiFpga_Status_ResourceNotFound_MESSAGE;
137 case NiFpga_Status_ResourceNotInitialized:
138 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
139 case NiFpga_Status_HardwareFault:
140 return NiFpga_Status_HardwareFault_MESSAGE;
141 case NiFpga_Status_IrqTimeout:
142 return NiFpga_Status_IrqTimeout_MESSAGE;
143 case SAMPLE_RATE_TOO_HIGH:
144 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
145 case VOLTAGE_OUT_OF_RANGE:
146 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
147 case LOOP_TIMING_ERROR:
148 return LOOP_TIMING_ERROR_MESSAGE;
149 case SPI_WRITE_NO_MOSI:
150 return SPI_WRITE_NO_MOSI_MESSAGE;
151 case SPI_READ_NO_MISO:
152 return SPI_READ_NO_MISO_MESSAGE;
153 case SPI_READ_NO_DATA:
154 return SPI_READ_NO_DATA_MESSAGE;
155 case INCOMPATIBLE_STATE:
156 return INCOMPATIBLE_STATE_MESSAGE;
157 case NO_AVAILABLE_RESOURCES:
158 return NO_AVAILABLE_RESOURCES_MESSAGE;
159 case RESOURCE_IS_ALLOCATED:
160 return RESOURCE_IS_ALLOCATED_MESSAGE;
161 case RESOURCE_OUT_OF_RANGE:
162 return RESOURCE_OUT_OF_RANGE_MESSAGE;
163 case HAL_INVALID_ACCUMULATOR_CHANNEL:
164 return HAL_INVALID_ACCUMULATOR_CHANNEL_MESSAGE;
165 case HAL_HANDLE_ERROR:
166 return HAL_HANDLE_ERROR_MESSAGE;
167 case NULL_PARAMETER:
168 return NULL_PARAMETER_MESSAGE;
169 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
170 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
171 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
172 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
173 case PARAMETER_OUT_OF_RANGE:
174 return PARAMETER_OUT_OF_RANGE_MESSAGE;
175 case HAL_COUNTER_NOT_SUPPORTED:
176 return HAL_COUNTER_NOT_SUPPORTED_MESSAGE;
177 case HAL_ERR_CANSessionMux_InvalidBuffer:
178 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
179 case HAL_ERR_CANSessionMux_MessageNotFound:
180 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
181 case HAL_WARN_CANSessionMux_NoToken:
182 return WARN_CANSessionMux_NoToken_MESSAGE;
183 case HAL_ERR_CANSessionMux_NotAllowed:
184 return ERR_CANSessionMux_NotAllowed_MESSAGE;
185 case HAL_ERR_CANSessionMux_NotInitialized:
186 return ERR_CANSessionMux_NotInitialized_MESSAGE;
Austin Schuh1e69f942020-11-14 15:06:14 -0800187 case VI_ERROR_SYSTEM_ERROR:
188 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
189 case VI_ERROR_INV_OBJECT:
190 return VI_ERROR_INV_OBJECT_MESSAGE;
191 case VI_ERROR_RSRC_LOCKED:
192 return VI_ERROR_RSRC_LOCKED_MESSAGE;
193 case VI_ERROR_RSRC_NFOUND:
194 return VI_ERROR_RSRC_NFOUND_MESSAGE;
195 case VI_ERROR_INV_RSRC_NAME:
196 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
197 case VI_ERROR_QUEUE_OVERFLOW:
198 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
199 case VI_ERROR_IO:
200 return VI_ERROR_IO_MESSAGE;
201 case VI_ERROR_ASRL_PARITY:
202 return VI_ERROR_ASRL_PARITY_MESSAGE;
203 case VI_ERROR_ASRL_FRAMING:
204 return VI_ERROR_ASRL_FRAMING_MESSAGE;
205 case VI_ERROR_ASRL_OVERRUN:
206 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
207 case VI_ERROR_RSRC_BUSY:
208 return VI_ERROR_RSRC_BUSY_MESSAGE;
209 case VI_ERROR_INV_PARAMETER:
210 return VI_ERROR_INV_PARAMETER_MESSAGE;
Brian Silverman8fce7482020-01-05 13:18:21 -0800211 case HAL_PWM_SCALE_ERROR:
212 return HAL_PWM_SCALE_ERROR_MESSAGE;
213 case HAL_SERIAL_PORT_NOT_FOUND:
214 return HAL_SERIAL_PORT_NOT_FOUND_MESSAGE;
215 case HAL_THREAD_PRIORITY_ERROR:
216 return HAL_THREAD_PRIORITY_ERROR_MESSAGE;
217 case HAL_THREAD_PRIORITY_RANGE_ERROR:
218 return HAL_THREAD_PRIORITY_RANGE_ERROR_MESSAGE;
219 case HAL_SERIAL_PORT_OPEN_ERROR:
220 return HAL_SERIAL_PORT_OPEN_ERROR_MESSAGE;
221 case HAL_SERIAL_PORT_ERROR:
222 return HAL_SERIAL_PORT_ERROR_MESSAGE;
223 case HAL_CAN_TIMEOUT:
224 return HAL_CAN_TIMEOUT_MESSAGE;
225 case ERR_FRCSystem_NetCommNotResponding:
226 return ERR_FRCSystem_NetCommNotResponding_MESSAGE;
227 case ERR_FRCSystem_NoDSConnection:
228 return ERR_FRCSystem_NoDSConnection_MESSAGE;
229 case HAL_CAN_BUFFER_OVERRUN:
230 return HAL_CAN_BUFFER_OVERRUN_MESSAGE;
231 case HAL_LED_CHANNEL_ERROR:
232 return HAL_LED_CHANNEL_ERROR_MESSAGE;
233 default:
234 return "Unknown error status";
235 }
236}
237
238HAL_RuntimeType HAL_GetRuntimeType(void) { return HAL_Athena; }
239
240int32_t HAL_GetFPGAVersion(int32_t* status) {
241 if (!global) {
242 *status = NiFpga_Status_ResourceNotInitialized;
243 return 0;
244 }
245 return global->readVersion(status);
246}
247
248int64_t HAL_GetFPGARevision(int32_t* status) {
249 if (!global) {
250 *status = NiFpga_Status_ResourceNotInitialized;
251 return 0;
252 }
253 return global->readRevision(status);
254}
255
256uint64_t HAL_GetFPGATime(int32_t* status) {
257 if (!global) {
258 *status = NiFpga_Status_ResourceNotInitialized;
259 return 0;
260 }
261 *status = 0;
262 uint64_t upper1 = global->readLocalTimeUpper(status);
263 uint32_t lower = global->readLocalTime(status);
264 uint64_t upper2 = global->readLocalTimeUpper(status);
265 if (*status != 0) return 0;
266 if (upper1 != upper2) {
267 // Rolled over between the lower call, reread lower
268 lower = global->readLocalTime(status);
269 if (*status != 0) return 0;
270 }
271 return (upper2 << 32) + lower;
272}
273
274uint64_t HAL_ExpandFPGATime(uint32_t unexpanded_lower, int32_t* status) {
275 // Capture the current FPGA time. This will give us the upper half of the
276 // clock.
277 uint64_t fpga_time = HAL_GetFPGATime(status);
278 if (*status != 0) return 0;
279
280 // Now, we need to detect the case where the lower bits rolled over after we
281 // sampled. In that case, the upper bits will be 1 bigger than they should
282 // be.
283
284 // Break it into lower and upper portions.
285 uint32_t lower = fpga_time & 0xffffffffull;
286 uint64_t upper = (fpga_time >> 32) & 0xffffffff;
287
288 // The time was sampled *before* the current time, so roll it back.
289 if (lower < unexpanded_lower) {
290 --upper;
291 }
292
293 return (upper << 32) + static_cast<uint64_t>(unexpanded_lower);
294}
295
296HAL_Bool HAL_GetFPGAButton(int32_t* status) {
297 if (!global) {
298 *status = NiFpga_Status_ResourceNotInitialized;
299 return false;
300 }
301 return global->readUserButton(status);
302}
303
304HAL_Bool HAL_GetSystemActive(int32_t* status) {
305 if (!watchdog) {
306 *status = NiFpga_Status_ResourceNotInitialized;
307 return false;
308 }
309 return watchdog->readStatus_SystemActive(status);
310}
311
312HAL_Bool HAL_GetBrownedOut(int32_t* status) {
313 if (!watchdog) {
314 *status = NiFpga_Status_ResourceNotInitialized;
315 return false;
316 }
317 return !(watchdog->readStatus_PowerAlive(status));
318}
319
320static bool killExistingProgram(int timeout, int mode) {
321 // Kill any previous robot programs
322 std::fstream fs;
323 // By making this both in/out, it won't give us an error if it doesnt exist
324 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
325 if (fs.bad()) return false;
326
327 pid_t pid = 0;
328 if (!fs.eof() && !fs.fail()) {
329 fs >> pid;
330 // see if the pid is around, but we don't want to mess with init id=1, or
331 // ourselves
332 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid()) {
333 wpi::outs() << "Killing previously running FRC program...\n";
334 kill(pid, SIGTERM); // try to kill it
335 std::this_thread::sleep_for(std::chrono::milliseconds(timeout));
336 if (kill(pid, 0) == 0) {
Austin Schuh1e69f942020-11-14 15:06:14 -0800337 // still not successful
Brian Silverman8fce7482020-01-05 13:18:21 -0800338 wpi::outs() << "FRC pid " << pid << " did not die within " << timeout
339 << "ms. Force killing with kill -9\n";
340 // Force kill -9
341 auto forceKill = kill(pid, SIGKILL);
342 if (forceKill != 0) {
343 auto errorMsg = std::strerror(forceKill);
344 wpi::outs() << "Kill -9 error: " << errorMsg << "\n";
345 }
346 // Give a bit of time for the kill to take place
347 std::this_thread::sleep_for(std::chrono::milliseconds(250));
348 }
349 }
350 }
351 fs.close();
352 // we will re-open it write only to truncate the file
353 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
354 fs.seekp(0);
355 pid = getpid();
356 fs << pid << std::endl;
357 fs.close();
358 return true;
359}
360
361HAL_Bool HAL_Initialize(int32_t timeout, int32_t mode) {
362 static std::atomic_bool initialized{false};
363 static wpi::mutex initializeMutex;
364 // Initial check, as if it's true initialization has finished
365 if (initialized) return true;
366
367 std::scoped_lock lock(initializeMutex);
368 // Second check in case another thread was waiting
369 if (initialized) return true;
370
371 hal::init::InitializeHAL();
372
373 hal::init::HAL_IsInitialized.store(true);
374
375 setlinebuf(stdin);
376 setlinebuf(stdout);
377 wpi::outs().SetUnbuffered();
378
379 prctl(PR_SET_PDEATHSIG, SIGTERM);
380
381 // Return false if program failed to kill an existing program
382 if (!killExistingProgram(timeout, mode)) {
383 return false;
384 }
385
386 FRC_NetworkCommunication_Reserve(nullptr);
387
388 std::atexit([]() {
389 // Unregister our new data condition variable.
390 setNewDataSem(nullptr);
391 });
392
Brian Silverman8fce7482020-01-05 13:18:21 -0800393 nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
Austin Schuh1e69f942020-11-14 15:06:14 -0800394 nLoadOut::getTargetClass();
Brian Silverman8fce7482020-01-05 13:18:21 -0800395
396 int32_t status = 0;
397 global.reset(tGlobal::create(&status));
398 watchdog.reset(tSysWatchdog::create(&status));
399
400 if (status != 0) return false;
401
402 HAL_InitializeDriverStation();
403
404 // Set WPI_Now to use FPGA timestamp
405 wpi::SetNowImpl([]() -> uint64_t {
406 int32_t status = 0;
407 uint64_t rv = HAL_GetFPGATime(&status);
408 if (status != 0) {
409 wpi::errs()
410 << "Call to HAL_GetFPGATime failed in wpi::Now() with status "
411 << status
412 << ". Initialization might have failed. Time will not be correct\n";
413 wpi::errs().flush();
414 return 0u;
415 }
416 return rv;
417 });
418
419 initialized = true;
420 return true;
421}
422
Austin Schuh1e69f942020-11-14 15:06:14 -0800423void HAL_Shutdown(void) {}
424
Brian Silverman8fce7482020-01-05 13:18:21 -0800425int64_t HAL_Report(int32_t resource, int32_t instanceNumber, int32_t context,
426 const char* feature) {
427 if (feature == nullptr) {
428 feature = "";
429 }
430
431 return FRC_NetworkCommunication_nUsageReporting_report(
432 resource, instanceNumber, context, feature);
433}
434
435// TODO: HACKS
436// No need for header definitions, as we should not run from user code.
437void NumericArrayResize(void) {}
438void RTSetCleanupProc(void) {}
439void EDVR_CreateReference(void) {}
440
441} // extern "C"