/* * Copyright 2014-2016 Cel Skeggs * * This file is part of the CCRE, the Common Chicken Runtime Engine. * * The CCRE is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) any * later version. * * The CCRE is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR * A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with the CCRE. If not, see <http://www.gnu.org/licenses/>. */ package ccre.frc.devices; import ccre.channel.BooleanInput; import ccre.channel.EventInput; import ccre.channel.FloatInput; import ccre.channel.FloatOutput; import ccre.ctrl.CombinationJoystickWithPOV; import ccre.ctrl.Joystick; import ccre.frc.Device; import ccre.frc.DeviceGroup; import ccre.frc.DeviceListPanel; import ccre.frc.JoystickHandler; import ccre.frc.JoystickHandler.ExternalJoystickHolder; import ccre.frc.components.SpacingComponent; import ccre.frc.components.TextComponent; import ccre.log.Logger; /** * A device representing a Joystick. This will have buttons and axes added * dynamically as needed. * * @author skeggsc */ public class JoystickDevice extends DeviceGroup { class ExternalJoystickAttachDevice extends Device { private final TextComponent status; ExternalJoystickAttachDevice(final JoystickHandler handler) { add(new SpacingComponent(40)); add(new TextComponent("External Joystick:")); add(status = new TextComponent("[UNATTACHED]", new String[] { "[UNATTACHED]", "[HOLD BUTTON FIRST]", "[ATTACHED]" }) { @Override protected void onPress(int x, int y) { if (joystickHolder.hasJoystick()) { joystickHolder.setJoystick(null); status.setLabel("[UNATTACHED]"); } else { JoystickHandler.JoystickWrapper joy = handler.getActivelyPressedJoystick(); if (joy == null) { status.setLabel("[UNATTACHED] Hold a Joystick button before clicking."); } else { Logger.info("Attaching joystick: " + joy); joystickHolder.setJoystick(joy); status.setLabel("[ATTACHED]: " + joy); } } } }); } } private final FloatControlDevice[] axes = new FloatControlDevice[6]; private final BooleanControlDevice[] buttons = new BooleanControlDevice[14]; private final BooleanControlDevice[] povAngles = new BooleanControlDevice[360]; private final FloatViewDevice[] rumbles = new FloatViewDevice[2]; private boolean wasAddedToMaster = false; private final DeviceListPanel master; private boolean isRoboRIO; private final ExternalJoystickHolder joystickHolder; /** * Create a new JoystickDevice with a name and a panel to contain this * Joystick. * * Make sure to call addToMaster instead of calling add directly. * * @param name the name of this device. * @param isRoboRIO if this is a Joystick on a roboRIO. * @param master the panel that will contain this device. * @param handler the JoystickHandler to use for connecting external * Joysticks. * @see #addToMaster() */ public JoystickDevice(String name, boolean isRoboRIO, DeviceListPanel master, JoystickHandler handler) { this.isRoboRIO = isRoboRIO; add(new HeadingDevice(name)); add(new ExternalJoystickAttachDevice(handler)); this.master = master; joystickHolder = new ExternalJoystickHolder(); } /** * Create a new JoystickDevice with a Joystick port number and a panel to * contain this Joystick. * * Make sure to call addToMaster instead of calling add directly. * * @param id the port number of this device. * @param isRoboRIO if this is a Joystick on a roboRIO. * @param master the panel that will contain this device. * @param handler the JoystickHandler to use for connecting external * Joysticks. * @see #addToMaster() */ public JoystickDevice(int id, boolean isRoboRIO, DeviceListPanel master, JoystickHandler handler) { this("Joystick " + id, isRoboRIO, master, handler); } /** * Add this Joystick to the device panel, if it hasn't been already added. * * @return this device, for method chaining. */ public synchronized JoystickDevice addToMaster() { if (!wasAddedToMaster) { wasAddedToMaster = true; master.add(this); } return this; } /** * Get the IJoystickWithPOV to access this Joystick. * * @param check when to update the Joystick's sources. * @return the Joystick. */ public Joystick getJoystick(EventInput check) { return new CombinationJoystickWithPOV(joystickHolder.getJoystick(check), new Joystick() { public BooleanInput button(int id) { if (id < 1 || id > buttons.length) { throw new IllegalArgumentException("Invalid button number: " + id); } if (buttons[id - 1] == null) { buttons[id - 1] = new BooleanControlDevice("Button " + id); add(buttons[id - 1]); addToMaster(); } return buttons[id - 1].asInput(); } public FloatInput axis(int id) { if (id < 1 || id > axes.length) { throw new IllegalArgumentException("Invalid axis number: " + id); } if (axes[id - 1] == null) { axes[id - 1] = new FloatControlDevice("Axis " + id); add(axes[id - 1]); addToMaster(); } return axes[id - 1].asInput(); } public BooleanInput isPOV(int direction) { if (!isRoboRIO) { throw new RuntimeException("POVs can only be accessed from a roboRIO!"); } if (direction < 0 || direction >= 360) { throw new IllegalArgumentException("POV directions must be in range 0 ... 359!"); } if (povAngles[direction] == null) { povAngles[direction] = new BooleanControlDevice("POV dir " + direction); add(povAngles[direction]); addToMaster(); } return povAngles[direction].asInput(); } @Override public FloatOutput rumble(boolean right) { int index = right ? 1 : 0; if (rumbles[index] == null) { rumbles[index] = new FloatViewDevice(right ? "Rumble Right" : "Rumble Left", 0, 1); rumbles[index].notifyDisabled(false); add(rumbles[index]); addToMaster(); } return rumbles[index]; } }); } }