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