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