/* * Copyright 2014-2015 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 java.util.HashMap; import ccre.channel.BooleanInput; import ccre.channel.BooleanOutput; import ccre.channel.EventInput; import ccre.channel.FloatInput; import ccre.channel.FloatOutput; import ccre.ctrl.ExtendedMotor; import ccre.ctrl.ExtendedMotorFailureException; import ccre.frc.Device; import ccre.frc.DeviceGroup; import ccre.frc.DeviceListPanel; /** * A virtual CANJaguar, which will contain any statuses, diagnostics, or outputs * requested by the application. * * @author skeggsc */ public class CANJaguarDevice extends DeviceGroup implements Disableable { private BooleanViewDevice enabled; private final HashMap<ExtendedMotor.StatusType, FloatControlDevice> statusDevices = new HashMap<ExtendedMotor.StatusType, FloatControlDevice>(); private final HashMap<ExtendedMotor.DiagnosticType, BooleanControlDevice> diagnosticDevices = new HashMap<ExtendedMotor.DiagnosticType, BooleanControlDevice>(); private final HashMap<ExtendedMotor.OutputControlMode, FloatViewDevice> outputDevices = new HashMap<ExtendedMotor.OutputControlMode, FloatViewDevice>(); private DeviceListPanel master; private TextualDisplayDevice pidStatus; private boolean wasAddedToMaster = false; /** * Creates a new CANJaguarDevice described as name with a specified * DeviceListPanel to contain this device. * * Make sure to call addToMaster - don't add this directly. * * @param name how to describe the CANJaguarDevice. * @param master the panel that contains this. * @see #addToMaster() */ public CANJaguarDevice(String name, DeviceListPanel master) { add(new HeadingDevice(name)); this.master = master; } /** * Creates a new CANJaguarDevice described as a CAN Jaguar of the given ID * with a specified DeviceListPanel to contain this device. * * Make sure to call addToMaster - don't add this directly. * * @param id the CAN bus ID of the device. * @param master the panel that contains this. * @see #addToMaster() */ public CANJaguarDevice(int id, DeviceListPanel master) { this("CAN Jaguar " + id, master); } /** * Add this device to its master panel, or do nothing if this has already * been done. * * @return this CANJaguarDevice, for method chaining purposes. */ public synchronized CANJaguarDevice addToMaster() { if (!wasAddedToMaster) { wasAddedToMaster = true; master.add(this); } return this; } /** * Gets the ExtendedMotor interface to pass to the emulated program. * * @return the ExtendedMotor of this CANJaguar. */ public ExtendedMotor getMotor() { return value; } private final ExtendedMotor value = new ExtendedMotor() { public void enable() throws ExtendedMotorFailureException { if (enabled == null) { enabled = add(new BooleanViewDevice("ENABLED")); } enabled.set(true); } public void disable() throws ExtendedMotorFailureException { if (enabled == null) { enabled = add(new BooleanViewDevice("ENABLED")); } enabled.set(false); } public BooleanOutput asEnable() { if (enabled == null) { enabled = add(new BooleanViewDevice("ENABLED")); } return enabled; } public FloatOutput asMode(OutputControlMode mode) { if (!outputDevices.containsKey(mode)) { outputDevices.put(mode, add(new FloatViewDevice(mode.toString()))); } return outputDevices.get(mode); } public FloatInput asStatus(StatusType type, EventInput updateOn) { if (!statusDevices.containsKey(type)) { statusDevices.put(type, add(new FloatControlDevice(type.toString()))); } return statusDevices.get(type).asInput(); } public Object getDiagnostics(DiagnosticType type) { switch (type) { case ANY_FAULT: case BUS_VOLTAGE_FAULT: case CURRENT_FAULT: case GATE_DRIVER_FAULT: case TEMPERATURE_FAULT: return getDiagnosticChannel(type).get(); case GENERIC_FAULT_MASK: case CAN_JAGUAR_FAULTS: return (getDiagnosticChannel(DiagnosticType.CURRENT_FAULT).get() ? 1 : 0) | (getDiagnosticChannel(DiagnosticType.TEMPERATURE_FAULT).get() ? 2 : 0) | (getDiagnosticChannel(DiagnosticType.BUS_VOLTAGE_FAULT).get() ? 4 : 0) | (getDiagnosticChannel(DiagnosticType.GATE_DRIVER_FAULT).get() ? 8 : 0); default: return null; } } public BooleanInput getDiagnosticChannel(DiagnosticType type) { if (type.isBooleanDiagnostic) { if (!diagnosticDevices.containsKey(type)) { diagnosticDevices.put(type, add(new BooleanControlDevice(type.toString()))); } return diagnosticDevices.get(type).asInput(); } else { return null; } } public boolean hasInternalPID() { return true; } public void setInternalPID(float P, float I, float D) throws ExtendedMotorFailureException { if (pidStatus == null) { pidStatus = add(new TextualDisplayDevice("...", 50)); } pidStatus.set("PID P=" + P + " I=" + I + " D=" + D); } }; @Override public void notifyDisabled(boolean disabled) { for (Device d : this) { if (d instanceof Disableable) { ((Disableable) d).notifyDisabled(disabled); } } } }