blob: 39802abe041bd247c46e3780d00645cf791f1414 [file] [log] [blame]
Brian Silverman26e4e522015-12-17 01:56:40 -05001/*----------------------------------------------------------------------------*/
2/* Copyright (c) FIRST 2008. All Rights Reserved.
3 */
4/* Open Source Software - may be modified and shared by FRC teams. The code */
5/* must be accompanied by the FIRST BSD license file in $(WIND_BASE)/WPILib. */
6/*----------------------------------------------------------------------------*/
7
8#include "DriverStation.h"
9#include "AnalogInput.h"
10#include "Timer.h"
11#include "NetworkCommunication/FRCComm.h"
12#include "MotorSafetyHelper.h"
13#include "Utility.h"
14#include "WPIErrors.h"
15#include <string.h>
16#include "Log.hpp"
17
18// set the logging level
19TLogLevel dsLogLevel = logDEBUG;
20const double JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL = 1.0;
21
22#define DS_LOG(level) \
23 if (level > dsLogLevel) ; \
24 else Log().Get(level)
25
26const uint32_t DriverStation::kJoystickPorts;
27
28/**
29 * DriverStation constructor.
30 *
31 * This is only called once the first time GetInstance() is called
32 */
33DriverStation::DriverStation() {
34 // All joysticks should default to having zero axes, povs and buttons, so
35 // uninitialized memory doesn't get sent to speed controllers.
36 for (unsigned int i = 0; i < kJoystickPorts; i++) {
37 m_joystickAxes[i].count = 0;
38 m_joystickPOVs[i].count = 0;
39 m_joystickButtons[i].count = 0;
40 m_joystickDescriptor[i].isXbox = 0;
41 m_joystickDescriptor[i].type = -1;
42 m_joystickDescriptor[i].name[0] = '\0';
43 }
44 // Register that semaphore with the network communications task.
45 // It will signal when new packet data is available.
46 HALSetNewDataSem(m_packetDataAvailableCond.native_handle());
47
48 AddToSingletonList();
49
50}
51
52void DriverStation::Run() {
53 int period = 0;
54 while (true) {
55 {
56 std::unique_lock<priority_mutex> lock(m_packetDataAvailableMutex);
57 m_packetDataAvailableCond.wait(lock);
58 }
59 GetData();
60 m_waitForDataCond.notify_all();
61
62 if (++period >= 4) {
63 MotorSafetyHelper::CheckMotors();
64 period = 0;
65 }
66 if (m_userInDisabled) HALNetworkCommunicationObserveUserProgramDisabled();
67 if (m_userInAutonomous) HALNetworkCommunicationObserveUserProgramAutonomous();
68 if (m_userInTeleop) HALNetworkCommunicationObserveUserProgramTeleop();
69 if (m_userInTest) HALNetworkCommunicationObserveUserProgramTest();
70 }
71}
72
73/**
74 * Return a reference to the singleton DriverStation.
75 * @return Pointer to the DS instance
76 */
77DriverStation &DriverStation::GetInstance() {
78 static DriverStation instance;
79 return instance;
80}
81
82/**
83 * Copy data from the DS task for the user.
84 * If no new data exists, it will just be returned, otherwise
85 * the data will be copied from the DS polling loop.
86 */
87void DriverStation::GetData() {
88 // Get the status of all of the joysticks
89 for (uint8_t stick = 0; stick < kJoystickPorts; stick++) {
90 HALGetJoystickAxes(stick, &m_joystickAxes[stick]);
91 HALGetJoystickPOVs(stick, &m_joystickPOVs[stick]);
92 HALGetJoystickButtons(stick, &m_joystickButtons[stick]);
93 HALGetJoystickDescriptor(stick, &m_joystickDescriptor[stick]);
94 }
95 m_newControlData.give();
96}
97
98/**
99 * Read the battery voltage.
100 *
101 * @return The battery voltage in Volts.
102 */
103float DriverStation::GetBatteryVoltage() const {
104 int32_t status = 0;
105 float voltage = getVinVoltage(&status);
106 wpi_setErrorWithContext(status, "getVinVoltage");
107
108 return voltage;
109}
110
111/**
112 * Reports errors related to unplugged joysticks
113 * Throttles the errors so that they don't overwhelm the DS
114 */
115void DriverStation::ReportJoystickUnpluggedError(std::string message) {
116 double currentTime = Timer::GetFPGATimestamp();
117 if (currentTime > m_nextMessageTime) {
118 ReportError(message);
119 m_nextMessageTime = currentTime + JOYSTICK_UNPLUGGED_MESSAGE_INTERVAL;
120 }
121}
122
123/**
124 * Returns the number of axes on a given joystick port
125 *
126 * @param stick The joystick port number
127 * @return The number of axes on the indicated joystick
128 */
129int DriverStation::GetStickAxisCount(uint32_t stick) const {
130 if (stick >= kJoystickPorts) {
131 wpi_setWPIError(BadJoystickIndex);
132 return 0;
133 }
134 HALJoystickAxes joystickAxes;
135 HALGetJoystickAxes(stick, &joystickAxes);
136 return joystickAxes.count;
137}
138
139/**
140 * Returns the name of the joystick at the given port
141 *
142 * @param stick The joystick port number
143 * @return The name of the joystick at the given port
144 */
145std::string DriverStation::GetJoystickName(uint32_t stick) const {
146 if (stick >= kJoystickPorts) {
147 wpi_setWPIError(BadJoystickIndex);
148 }
149 std::string retVal(m_joystickDescriptor[0].name);
150 return retVal;
151}
152
153/**
154 * Returns the type of joystick at a given port
155 *
156 * @param stick The joystick port number
157 * @return The HID type of joystick at the given port
158 */
159int DriverStation::GetJoystickType(uint32_t stick) const {
160 if (stick >= kJoystickPorts) {
161 wpi_setWPIError(BadJoystickIndex);
162 return -1;
163 }
164 return (int)m_joystickDescriptor[stick].type;
165}
166
167/**
168 * Returns a boolean indicating if the controller is an xbox controller.
169 *
170 * @param stick The joystick port number
171 * @return A boolean that is true if the controller is an xbox controller.
172 */
173bool DriverStation::GetJoystickIsXbox(uint32_t stick) const {
174 if (stick >= kJoystickPorts) {
175 wpi_setWPIError(BadJoystickIndex);
176 return false;
177 }
178 return (bool)m_joystickDescriptor[stick].isXbox;
179}
180
181/**
182 * Returns the types of Axes on a given joystick port
183 *
184 * @param stick The joystick port number and the target axis
185 * @return What type of axis the axis is reporting to be
186 */
187int DriverStation::GetJoystickAxisType(uint32_t stick, uint8_t axis) const {
188 if (stick >= kJoystickPorts) {
189 wpi_setWPIError(BadJoystickIndex);
190 return -1;
191 }
192 return m_joystickDescriptor[stick].axisTypes[axis];
193}
194
195/**
196 * Returns the number of POVs on a given joystick port
197 *
198 * @param stick The joystick port number
199 * @return The number of POVs on the indicated joystick
200 */
201int DriverStation::GetStickPOVCount(uint32_t stick) const {
202 if (stick >= kJoystickPorts) {
203 wpi_setWPIError(BadJoystickIndex);
204 return 0;
205 }
206 HALJoystickPOVs joystickPOVs;
207 HALGetJoystickPOVs(stick, &joystickPOVs);
208 return joystickPOVs.count;
209}
210
211/**
212 * Returns the number of buttons on a given joystick port
213 *
214 * @param stick The joystick port number
215 * @return The number of buttons on the indicated joystick
216 */
217int DriverStation::GetStickButtonCount(uint32_t stick) const {
218 if (stick >= kJoystickPorts) {
219 wpi_setWPIError(BadJoystickIndex);
220 return 0;
221 }
222 HALJoystickButtons joystickButtons;
223 HALGetJoystickButtons(stick, &joystickButtons);
224 return joystickButtons.count;
225}
226
227/**
228 * Get the value of the axis on a joystick.
229 * This depends on the mapping of the joystick connected to the specified port.
230 *
231 * @param stick The joystick to read.
232 * @param axis The analog axis value to read from the joystick.
233 * @return The value of the axis on the joystick.
234 */
235float DriverStation::GetStickAxis(uint32_t stick, uint32_t axis) {
236 if (stick >= kJoystickPorts) {
237 wpi_setWPIError(BadJoystickIndex);
238 return 0;
239 }
240
241 if (axis >= m_joystickAxes[stick].count) {
242 if (axis >= kMaxJoystickAxes) {
243 wpi_setWPIError(BadJoystickAxis);
244 }
245 else {
246 ReportJoystickUnpluggedError(
247 "WARNING: Joystick Axis missing, check if all controllers are "
248 "plugged in\n");
249 }
250 return 0.0f;
251 }
252
253 int8_t value = m_joystickAxes[stick].axes[axis];
254
255 if (value < 0) {
256 return value / 128.0f;
257 } else {
258 return value / 127.0f;
259 }
260}
261
262/**
263 * Get the state of a POV on the joystick.
264 *
265 * @return the angle of the POV in degrees, or -1 if the POV is not pressed.
266 */
267int DriverStation::GetStickPOV(uint32_t stick, uint32_t pov) {
268 if (stick >= kJoystickPorts) {
269 wpi_setWPIError(BadJoystickIndex);
270 return -1;
271 }
272
273 if (pov >= m_joystickPOVs[stick].count) {
274 if (pov >= kMaxJoystickPOVs) {
275 wpi_setWPIError(BadJoystickAxis);
276 }
277 else {
278 ReportJoystickUnpluggedError(
279 "WARNING: Joystick POV missing, check if all controllers are plugged "
280 "in\n");
281 }
282 return -1;
283 }
284
285 return m_joystickPOVs[stick].povs[pov];
286}
287
288/**
289 * The state of the buttons on the joystick.
290 *
291 * @param stick The joystick to read.
292 * @return The state of the buttons on the joystick.
293 */
294uint32_t DriverStation::GetStickButtons(uint32_t stick) const {
295 if (stick >= kJoystickPorts) {
296 wpi_setWPIError(BadJoystickIndex);
297 return 0;
298 }
299
300 return m_joystickButtons[stick].buttons;
301}
302
303/**
304 * The state of one joystick button. Button indexes begin at 1.
305 *
306 * @param stick The joystick to read.
307 * @param button The button index, beginning at 1.
308 * @return The state of the joystick button.
309 */
310bool DriverStation::GetStickButton(uint32_t stick, uint8_t button) {
311 if (stick >= kJoystickPorts) {
312 wpi_setWPIError(BadJoystickIndex);
313 return false;
314 }
315
316 if (button > m_joystickButtons[stick].count) {
317 ReportJoystickUnpluggedError(
318 "WARNING: Joystick Button missing, check if all controllers are "
319 "plugged in\n");
320 return false;
321 }
322 if (button == 0) {
323 ReportJoystickUnpluggedError(
324 "ERROR: Button indexes begin at 1 in WPILib for C++ and Java");
325 return false;
326 }
327 return ((0x1 << (button - 1)) & m_joystickButtons[stick].buttons) != 0;
328}
329
330/**
331 * Check if the DS has enabled the robot
332 * @return True if the robot is enabled and the DS is connected
333 */
334bool DriverStation::IsEnabled() const {
335 HALControlWord controlWord;
336 memset(&controlWord, 0, sizeof(controlWord));
337 HALGetControlWord(&controlWord);
338 return controlWord.enabled && controlWord.dsAttached;
339}
340
341/**
342 * Check if the robot is disabled
343 * @return True if the robot is explicitly disabled or the DS is not connected
344 */
345bool DriverStation::IsDisabled() const {
346 HALControlWord controlWord;
347 memset(&controlWord, 0, sizeof(controlWord));
348 HALGetControlWord(&controlWord);
349 return !(controlWord.enabled && controlWord.dsAttached);
350}
351
352/**
353 * Check if the DS is commanding autonomous mode
354 * @return True if the robot is being commanded to be in autonomous mode
355 */
356bool DriverStation::IsAutonomous() const {
357 HALControlWord controlWord;
358 memset(&controlWord, 0, sizeof(controlWord));
359 HALGetControlWord(&controlWord);
360 return controlWord.autonomous;
361}
362
363/**
364 * Check if the DS is commanding teleop mode
365 * @return True if the robot is being commanded to be in teleop mode
366 */
367bool DriverStation::IsOperatorControl() const {
368 HALControlWord controlWord;
369 memset(&controlWord, 0, sizeof(controlWord));
370 HALGetControlWord(&controlWord);
371 return !(controlWord.autonomous || controlWord.test);
372}
373
374/**
375 * Check if the DS is commanding test mode
376 * @return True if the robot is being commanded to be in test mode
377 */
378bool DriverStation::IsTest() const {
379 HALControlWord controlWord;
380 HALGetControlWord(&controlWord);
381 return controlWord.test;
382}
383
384/**
385 * Check if the DS is attached
386 * @return True if the DS is connected to the robot
387 */
388bool DriverStation::IsDSAttached() const {
389 HALControlWord controlWord;
390 memset(&controlWord, 0, sizeof(controlWord));
391 HALGetControlWord(&controlWord);
392 return controlWord.dsAttached;
393}
394
395/**
396 * @return always true in simulation
397 */
398bool DriverStation::IsSysActive() const {
399 return true;
400}
401
402/**
403 * @return always false in simulation
404 */
405bool DriverStation::IsSysBrownedOut() const {
406 return false;
407}
408
409/**
410 * Has a new control packet from the driver station arrived since the last time
411 * this function was called?
412 * Warning: If you call this function from more than one place at the same time,
413 * you will not get the get the intended behaviour.
414 * @return True if the control data has been updated since the last call.
415 */
416bool DriverStation::IsNewControlData() const {
417 return m_newControlData.tryTake() == false;
418}
419
420/**
421 * Is the driver station attached to a Field Management System?
422 * @return True if the robot is competing on a field being controlled by a Field
423 * Management System
424 */
425bool DriverStation::IsFMSAttached() const {
426 HALControlWord controlWord;
427 HALGetControlWord(&controlWord);
428 return controlWord.fmsAttached;
429}
430
431/**
432 * Return the alliance that the driver station says it is on.
433 * This could return kRed or kBlue
434 * @return The Alliance enum (kRed, kBlue or kInvalid)
435 */
436DriverStation::Alliance DriverStation::GetAlliance() const {
437 HALAllianceStationID allianceStationID;
438 HALGetAllianceStation(&allianceStationID);
439 switch (allianceStationID) {
440 case kHALAllianceStationID_red1:
441 case kHALAllianceStationID_red2:
442 case kHALAllianceStationID_red3:
443 return kRed;
444 case kHALAllianceStationID_blue1:
445 case kHALAllianceStationID_blue2:
446 case kHALAllianceStationID_blue3:
447 return kBlue;
448 default:
449 return kInvalid;
450 }
451}
452
453/**
454 * Return the driver station location on the field
455 * This could return 1, 2, or 3
456 * @return The location of the driver station (1-3, 0 for invalid)
457 */
458uint32_t DriverStation::GetLocation() const {
459 HALAllianceStationID allianceStationID;
460 HALGetAllianceStation(&allianceStationID);
461 switch (allianceStationID) {
462 case kHALAllianceStationID_red1:
463 case kHALAllianceStationID_blue1:
464 return 1;
465 case kHALAllianceStationID_red2:
466 case kHALAllianceStationID_blue2:
467 return 2;
468 case kHALAllianceStationID_red3:
469 case kHALAllianceStationID_blue3:
470 return 3;
471 default:
472 return 0;
473 }
474}
475
476/**
477 * Wait until a new packet comes from the driver station
478 * This blocks on a semaphore, so the waiting is efficient.
479 * This is a good way to delay processing until there is new driver station data
480 * to act on
481 */
482void DriverStation::WaitForData() {
483 std::unique_lock<priority_mutex> lock(m_waitForDataMutex);
484 m_waitForDataCond.wait(lock);
485}
486
487/**
488 * Return the approximate match time
489 * The FMS does not send an official match time to the robots, but does send an
490 * approximate match time.
491 * The value will count down the time remaining in the current period (auto or
492 * teleop).
493 * Warning: This is not an official time (so it cannot be used to dispute ref
494 * calls or guarantee that a function
495 * will trigger before the match ends)
496 * The Practice Match function of the DS approximates the behaviour seen on the
497 * field.
498 * @return Time remaining in current match period (auto or teleop)
499 */
500double DriverStation::GetMatchTime() const {
501 float matchTime;
502 HALGetMatchTime(&matchTime);
503 return (double)matchTime;
504}
505
506/**
507 * Report an error to the DriverStation messages window.
508 * The error is also printed to the program console.
509 */
510void DriverStation::ReportError(std::string error) {
511 std::cout << error << std::endl;
512
513 HALControlWord controlWord;
514 HALGetControlWord(&controlWord);
515 if (controlWord.dsAttached) {
516 HALSetErrorData(error.c_str(), error.size(), 0);
517 }
518}