blob: b1ffcb1c209f1af529acd900508034f08754fbb3 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001#include "HAL/HAL.hpp"
2
3#include "HAL/Port.h"
4#include "HAL/Errors.hpp"
5#include "ctre/ctre.h"
6#include "visa/visa.h"
7#include "ChipObject.h"
8#include "FRC_NetworkCommunication/FRCComm.h"
9#include "FRC_NetworkCommunication/UsageReporting.h"
10#include "FRC_NetworkCommunication/LoadOut.h"
11#include "FRC_NetworkCommunication/CANSessionMux.h"
12#include <cstdlib>
13#include <fstream>
14#include <iostream>
15#include <unistd.h>
16#include <sys/prctl.h>
17#include <signal.h> // linux for kill
18const uint32_t solenoid_kNumDO7_0Elements = 8;
19const uint32_t dio_kNumSystems = tDIO::kNumSystems;
20const uint32_t interrupt_kNumSystems = tInterrupt::kNumSystems;
21const uint32_t kSystemClockTicksPerMicrosecond = 40;
22
23static tGlobal *global = nullptr;
24static tSysWatchdog *watchdog = nullptr;
25
26void* getPort(uint8_t pin)
27{
28 Port* port = new Port();
29 port->pin = pin;
30 port->module = 1;
31 return port;
32}
33
34/**
35 * @deprecated Uses module numbers
36 */
37void* getPortWithModule(uint8_t module, uint8_t pin)
38{
39 Port* port = new Port();
40 port->pin = pin;
41 port->module = module;
42 return port;
43}
44
45void freePort(void* port_pointer)
46{
47 Port* port = (Port*) port_pointer;
48 delete port;
49}
50
51const char* getHALErrorMessage(int32_t code)
52{
53 switch(code) {
54 case 0:
55 return "";
56 case CTR_RxTimeout:
57 return CTR_RxTimeout_MESSAGE;
58 case CTR_TxTimeout:
59 return CTR_TxTimeout_MESSAGE;
60 case CTR_InvalidParamValue:
61 return CTR_InvalidParamValue_MESSAGE;
62 case CTR_UnexpectedArbId:
63 return CTR_UnexpectedArbId_MESSAGE;
64 case CTR_TxFailed:
65 return CTR_TxFailed_MESSAGE;
66 case CTR_SigNotUpdated:
67 return CTR_SigNotUpdated_MESSAGE;
68 case NiFpga_Status_FifoTimeout:
69 return NiFpga_Status_FifoTimeout_MESSAGE;
70 case NiFpga_Status_TransferAborted:
71 return NiFpga_Status_TransferAborted_MESSAGE;
72 case NiFpga_Status_MemoryFull:
73 return NiFpga_Status_MemoryFull_MESSAGE;
74 case NiFpga_Status_SoftwareFault:
75 return NiFpga_Status_SoftwareFault_MESSAGE;
76 case NiFpga_Status_InvalidParameter:
77 return NiFpga_Status_InvalidParameter_MESSAGE;
78 case NiFpga_Status_ResourceNotFound:
79 return NiFpga_Status_ResourceNotFound_MESSAGE;
80 case NiFpga_Status_ResourceNotInitialized:
81 return NiFpga_Status_ResourceNotInitialized_MESSAGE;
82 case NiFpga_Status_HardwareFault:
83 return NiFpga_Status_HardwareFault_MESSAGE;
84 case NiFpga_Status_IrqTimeout:
85 return NiFpga_Status_IrqTimeout_MESSAGE;
86 case SAMPLE_RATE_TOO_HIGH:
87 return SAMPLE_RATE_TOO_HIGH_MESSAGE;
88 case VOLTAGE_OUT_OF_RANGE:
89 return VOLTAGE_OUT_OF_RANGE_MESSAGE;
90 case LOOP_TIMING_ERROR:
91 return LOOP_TIMING_ERROR_MESSAGE;
92 case SPI_WRITE_NO_MOSI:
93 return SPI_WRITE_NO_MOSI_MESSAGE;
94 case SPI_READ_NO_MISO:
95 return SPI_READ_NO_MISO_MESSAGE;
96 case SPI_READ_NO_DATA:
97 return SPI_READ_NO_DATA_MESSAGE;
98 case INCOMPATIBLE_STATE:
99 return INCOMPATIBLE_STATE_MESSAGE;
100 case NO_AVAILABLE_RESOURCES:
101 return NO_AVAILABLE_RESOURCES_MESSAGE;
102 case NULL_PARAMETER:
103 return NULL_PARAMETER_MESSAGE;
104 case ANALOG_TRIGGER_LIMIT_ORDER_ERROR:
105 return ANALOG_TRIGGER_LIMIT_ORDER_ERROR_MESSAGE;
106 case ANALOG_TRIGGER_PULSE_OUTPUT_ERROR:
107 return ANALOG_TRIGGER_PULSE_OUTPUT_ERROR_MESSAGE;
108 case PARAMETER_OUT_OF_RANGE:
109 return PARAMETER_OUT_OF_RANGE_MESSAGE;
110 case ERR_CANSessionMux_InvalidBuffer:
111 return ERR_CANSessionMux_InvalidBuffer_MESSAGE;
112 case ERR_CANSessionMux_MessageNotFound:
113 return ERR_CANSessionMux_MessageNotFound_MESSAGE;
114 case WARN_CANSessionMux_NoToken:
115 return WARN_CANSessionMux_NoToken_MESSAGE;
116 case ERR_CANSessionMux_NotAllowed:
117 return ERR_CANSessionMux_NotAllowed_MESSAGE;
118 case ERR_CANSessionMux_NotInitialized:
119 return ERR_CANSessionMux_NotInitialized_MESSAGE;
120 case VI_ERROR_SYSTEM_ERROR:
121 return VI_ERROR_SYSTEM_ERROR_MESSAGE;
122 case VI_ERROR_INV_OBJECT:
123 return VI_ERROR_INV_OBJECT_MESSAGE;
124 case VI_ERROR_RSRC_LOCKED:
125 return VI_ERROR_RSRC_LOCKED_MESSAGE;
126 case VI_ERROR_RSRC_NFOUND:
127 return VI_ERROR_RSRC_NFOUND_MESSAGE;
128 case VI_ERROR_INV_RSRC_NAME:
129 return VI_ERROR_INV_RSRC_NAME_MESSAGE;
130 case VI_ERROR_QUEUE_OVERFLOW:
131 return VI_ERROR_QUEUE_OVERFLOW_MESSAGE;
132 case VI_ERROR_IO:
133 return VI_ERROR_IO_MESSAGE;
134 case VI_ERROR_ASRL_PARITY:
135 return VI_ERROR_ASRL_PARITY_MESSAGE;
136 case VI_ERROR_ASRL_FRAMING:
137 return VI_ERROR_ASRL_FRAMING_MESSAGE;
138 case VI_ERROR_ASRL_OVERRUN:
139 return VI_ERROR_ASRL_OVERRUN_MESSAGE;
140 case VI_ERROR_RSRC_BUSY:
141 return VI_ERROR_RSRC_BUSY_MESSAGE;
142 case VI_ERROR_INV_PARAMETER:
143 return VI_ERROR_INV_PARAMETER_MESSAGE;
144 default:
145 return "Unknown error status";
146 }
147}
148
149/**
150 * Return the FPGA Version number.
151 * For now, expect this to be competition year.
152 * @return FPGA Version number.
153 */
154uint16_t getFPGAVersion(int32_t *status)
155{
156 if (!global) {
157 *status = NiFpga_Status_ResourceNotInitialized;
158 return 0;
159 }
160 return global->readVersion(status);
161}
162
163/**
164 * Return the FPGA Revision number.
165 * The format of the revision is 3 numbers.
166 * The 12 most significant bits are the Major Revision.
167 * the next 8 bits are the Minor Revision.
168 * The 12 least significant bits are the Build Number.
169 * @return FPGA Revision number.
170 */
171uint32_t getFPGARevision(int32_t *status)
172{
173 if (!global) {
174 *status = NiFpga_Status_ResourceNotInitialized;
175 return 0;
176 }
177 return global->readRevision(status);
178}
179
180/**
181 * Read the microsecond-resolution timer on the FPGA.
182 *
183 * @return The current time in microseconds according to the FPGA (since FPGA reset).
184 */
185uint32_t getFPGATime(int32_t *status)
186{
187 if (!global) {
188 *status = NiFpga_Status_ResourceNotInitialized;
189 return 0;
190 }
191 return global->readLocalTime(status);
192}
193
194/**
195 * Get the state of the "USER" button on the RoboRIO
196 * @return true if the button is currently pressed down
197 */
198bool getFPGAButton(int32_t *status)
199{
200 if (!global) {
201 *status = NiFpga_Status_ResourceNotInitialized;
202 return false;
203 }
204 return global->readUserButton(status);
205}
206
207int HALSetErrorData(const char *errors, int errorsLength, int wait_ms)
208{
209 return setErrorData(errors, errorsLength, wait_ms);
210}
211
212
213bool HALGetSystemActive(int32_t *status)
214{
215 if (!watchdog) {
216 *status = NiFpga_Status_ResourceNotInitialized;
217 return false;
218 }
219 return watchdog->readStatus_SystemActive(status);
220}
221
222bool HALGetBrownedOut(int32_t *status)
223{
224 if (!watchdog) {
225 *status = NiFpga_Status_ResourceNotInitialized;
226 return false;
227 }
228 return !(watchdog->readStatus_PowerAlive(status));
229}
230
231static void HALCleanupAtExit() {
232 global = nullptr;
233 watchdog = nullptr;
234}
235
236/**
237 * Call this to start up HAL. This is required for robot programs.
238 */
239int HALInitialize(int mode)
240{
241 setlinebuf(stdin);
242 setlinebuf(stdout);
243
244 prctl(PR_SET_PDEATHSIG, SIGTERM);
245
246 FRC_NetworkCommunication_Reserve(nullptr);
247 // image 4; Fixes errors caused by multiple processes. Talk to NI about this
248 nFPGA::nRoboRIO_FPGANamespace::g_currentTargetClass =
249 nLoadOut::kTargetClass_RoboRIO;
250
251 int32_t status = 0;
252 global = tGlobal::create(&status);
253 watchdog = tSysWatchdog::create(&status);
254
255 std::atexit(HALCleanupAtExit);
256
257 // Kill any previous robot programs
258 std::fstream fs;
259 // By making this both in/out, it won't give us an error if it doesnt exist
260 fs.open("/var/lock/frc.pid", std::fstream::in | std::fstream::out);
261 if (fs.bad())
262 return 0;
263
264 pid_t pid = 0;
265 if (!fs.eof() && !fs.fail())
266 {
267 fs >> pid;
268 //see if the pid is around, but we don't want to mess with init id=1, or ourselves
269 if (pid >= 2 && kill(pid, 0) == 0 && pid != getpid())
270 {
271 std::cout << "Killing previously running FRC program..."
272 << std::endl;
273 kill(pid, SIGTERM); // try to kill it
274 delayMillis(100);
275 if (kill(pid, 0) == 0)
276 {
277 // still not successfull
278 if (mode == 0)
279 {
280 std::cout << "FRC pid " << pid
281 << " did not die within 110ms. Aborting"
282 << std::endl;
283 return 0; // just fail
284 }
285 else if (mode == 1) // kill -9 it
286 kill(pid, SIGKILL);
287 else
288 {
289 std::cout << "WARNING: FRC pid " << pid
290 << " did not die within 110ms." << std::endl;
291 }
292 }
293
294 }
295 }
296 fs.close();
297 // we will re-open it write only to truncate the file
298 fs.open("/var/lock/frc.pid", std::fstream::out | std::fstream::trunc);
299 fs.seekp(0);
300 pid = getpid();
301 fs << pid << std::endl;
302 fs.close();
303 return 1;
304}
305
306uint32_t HALReport(uint8_t resource, uint8_t instanceNumber, uint8_t context,
307 const char *feature)
308{
309 if(feature == NULL)
310 {
311 feature = "";
312 }
313
314 return FRC_NetworkCommunication_nUsageReporting_report(resource, instanceNumber, context, feature);
315}
316
317// TODO: HACKS
318void NumericArrayResize()
319{
320}
321void RTSetCleanupProc()
322{
323}
324void EDVR_CreateReference()
325{
326}
327void Occur()
328{
329}
330
331void imaqGetErrorText()
332{
333}
334void imaqGetLastError()
335{
336}
337void niTimestamp64()
338{
339}