001/*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005package edu.wpi.first.wpilibj.livewindow;
006
007import edu.wpi.first.wpilibj.command.Scheduler;
008import edu.wpi.first.wpilibj.networktables.NetworkTable;
009import edu.wpi.first.wpilibj.tables.ITable;
010import java.util.Enumeration;
011import java.util.Hashtable;
012import java.util.Vector;
013
014/**
015 * A LiveWindow component is a device (sensor or actuator) that should be added to the
016 * SmartDashboard in test mode. The components are cached until the first time the robot
017 * enters Test mode. This allows the components to be inserted, then renamed.
018 * @author brad
019 */
020class LiveWindowComponent {
021
022    String m_subsystem;
023    String m_name;
024    boolean m_isSensor;
025
026    public LiveWindowComponent(String subsystem, String name, boolean isSensor) {
027        m_subsystem = subsystem;
028        m_name = name;
029        m_isSensor = isSensor;
030    }
031
032    public String getName() {
033        return m_name;
034    }
035
036    public String getSubsystem() {
037        return m_subsystem;
038    }
039
040    public boolean isSensor() {
041        return m_isSensor;
042    }
043}
044
045/**
046 * The LiveWindow class is the public interface for putting sensors and
047 * actuators on the LiveWindow.
048 *
049 * @author Alex Henning
050 */
051public class LiveWindow {
052
053    private static Vector sensors = new Vector();
054//    private static Vector actuators = new Vector();
055    private static Hashtable components = new Hashtable();
056    private static ITable livewindowTable;
057    private static ITable statusTable;
058    private static boolean liveWindowEnabled = false;
059    private static boolean firstTime = true;
060
061    /**
062     * Initialize all the LiveWindow elements the first time we enter LiveWindow
063     * mode. By holding off creating the NetworkTable entries, it allows them to
064     * be redefined before the first time in LiveWindow mode. This allows
065     * default sensor and actuator values to be created that are replaced with
066     * the custom names from users calling addActuator and addSensor.
067     */
068    private static void initializeLiveWindowComponents() {
069        System.out.println("Initializing the components first time");
070        livewindowTable = NetworkTable.getTable("LiveWindow");
071        statusTable = livewindowTable.getSubTable("~STATUS~");
072        for (Enumeration e = components.keys(); e.hasMoreElements();) {
073            LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
074            LiveWindowComponent c = (LiveWindowComponent) components.get(component);
075            String subsystem = c.getSubsystem();
076            String name = c.getName();
077            System.out.println("Initializing table for '" + subsystem + "' '" + name + "'");
078            livewindowTable.getSubTable(subsystem).putString("~TYPE~", "LW Subsystem");
079            ITable table = livewindowTable.getSubTable(subsystem).getSubTable(name);
080            table.putString("~TYPE~", component.getSmartDashboardType());
081            table.putString("Name", name);
082            table.putString("Subsystem", subsystem);
083            component.initTable(table);
084            if (c.isSensor()) {
085                sensors.addElement(component);
086            }
087        }
088    }
089
090    /**
091     * Set the enabled state of LiveWindow. If it's being enabled, turn off the
092     * scheduler and remove all the commands from the queue and enable all the
093     * components registered for LiveWindow. If it's being disabled, stop all
094     * the registered components and reenable the scheduler. TODO: add code to
095     * disable PID loops when enabling LiveWindow. The commands should reenable
096     * the PID loops themselves when they get rescheduled. This prevents arms
097     * from starting to move around, etc. after a period of adjusting them in
098     * LiveWindow mode.
099     */
100    public static void setEnabled(boolean enabled) {
101        if (liveWindowEnabled != enabled) {
102            if (enabled) {
103                System.out.println("Starting live window mode.");
104                if (firstTime) {
105                    initializeLiveWindowComponents();
106                    firstTime = false;
107                }
108                Scheduler.getInstance().disable();
109                Scheduler.getInstance().removeAll();
110                for (Enumeration e = components.keys(); e.hasMoreElements();) {
111                    LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
112                    component.startLiveWindowMode();
113                }
114            } else {
115                System.out.println("stopping live window mode.");
116                for (Enumeration e = components.keys(); e.hasMoreElements();) {
117                    LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
118                    component.stopLiveWindowMode();
119                }
120                Scheduler.getInstance().enable();
121            }
122            liveWindowEnabled = enabled;
123            statusTable.putBoolean("LW Enabled", enabled);
124        }
125    }
126
127    /**
128     * The run method is called repeatedly to keep the values refreshed on the screen in
129     * test mode.
130     */
131    public static void run() {
132        updateValues();
133    }
134
135    /**
136     * Add a Sensor associated with the subsystem and with call it by the given
137     * name.
138     *
139     * @param subsystem The subsystem this component is part of.
140     * @param name The name of this component.
141     * @param component A LiveWindowSendable component that represents a sensor.
142     */
143    public static void addSensor(String subsystem, String name, LiveWindowSendable component) {
144        components.put(component, new LiveWindowComponent(subsystem, name, true));
145    }
146
147    /**
148     * Add an Actuator associated with the subsystem and with call it by the
149     * given name.
150     *
151     * @param subsystem The subsystem this component is part of.
152     * @param name The name of this component.
153     * @param component A LiveWindowSendable component that represents a
154     * actuator.
155     */
156    public static void addActuator(String subsystem, String name, LiveWindowSendable component) {
157        components.put(component, new LiveWindowComponent(subsystem, name, false));
158    }
159
160    /**
161     * Puts all sensor values on the live window.
162     */
163    private static void updateValues() {
164        //TODO: gross - needs to be sped up
165        for (int i = 0; i < sensors.size(); i++) {
166            LiveWindowSendable lws = (LiveWindowSendable) sensors.elementAt(i);
167            lws.updateTable();
168        }
169        // TODO: Add actuators?
170        // TODO: Add better rate limiting.
171    }
172
173    /**
174     * Add Sensor to LiveWindow. The components are shown with the type and
175     * channel like this: Gyro[1] for a gyro object connected to the first
176     * analog channel.
177     *
178     * @param moduleType A string indicating the type of the module used in the
179     * naming (above)
180     * @param channel The channel number the device is connected to
181     * @param component A reference to the object being added
182     */
183    public static void addSensor(String moduleType, int channel, LiveWindowSendable component) {
184        addSensor("Ungrouped", moduleType + "[" + channel + "]", component);
185        if (sensors.contains(component)) {
186            sensors.removeElement(component);
187        }
188        sensors.addElement(component);
189    }
190
191    /**
192     * Add Actuator to LiveWindow. The components are shown with the module
193     * type, slot and channel like this: Servo[1,2] for a servo object connected
194     * to the first digital module and PWM port 2.
195     *
196     * @param moduleType A string that defines the module name in the label for
197     * the value
198     * @param channel The channel number the device is plugged into (usually
199     * PWM)
200     * @param component The reference to the object being added
201     */
202    public static void addActuator(String moduleType, int channel, LiveWindowSendable component) {
203        addActuator("Ungrouped", moduleType + "[" + channel + "]", component);
204    }
205
206    /**
207     * Add Actuator to LiveWindow. The components are shown with the module
208     * type, slot and channel like this: Servo[1,2] for a servo object connected
209     * to the first digital module and PWM port 2.
210     *
211     * @param moduleType A string that defines the module name in the label for
212     * the value
213     * @param moduleNumber The number of the particular module type
214     * @param channel The channel number the device is plugged into (usually
215     * PWM)
216     * @param component The reference to the object being added
217     */
218    public static void addActuator(String moduleType, int moduleNumber, int channel, LiveWindowSendable component) {
219        addActuator("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]", component);
220    }
221}