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