001 /*
002 * To change this template, choose Tools | Templates
003 * and open the template in the editor.
004 */
005 package edu.wpi.first.wpilibj.livewindow;
006
007 import edu.wpi.first.wpilibj.command.Scheduler;
008 import edu.wpi.first.wpilibj.networktables.NetworkTable;
009 import edu.wpi.first.wpilibj.tables.ITable;
010 import java.util.Enumeration;
011 import java.util.Hashtable;
012 import 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 */
020 class 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 */
051 public 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 = NetworkTable.getTable("LiveWindow");
057 private static ITable statusTable = livewindowTable.getSubTable("~STATUS~");
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 for (Enumeration e = components.keys(); e.hasMoreElements();) {
071 LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
072 LiveWindowComponent c = (LiveWindowComponent) components.get(component);
073 String subsystem = c.getSubsystem();
074 String name = c.getName();
075 System.out.println("Initializing table for '" + subsystem + "' '" + name + "'");
076 livewindowTable.getSubTable(subsystem).putString("~TYPE~", "LW Subsystem");
077 ITable table = livewindowTable.getSubTable(subsystem).getSubTable(name);
078 table.putString("~TYPE~", component.getSmartDashboardType());
079 table.putString("Name", name);
080 table.putString("Subsystem", subsystem);
081 component.initTable(table);
082 if (c.isSensor()) {
083 sensors.addElement(component);
084 }
085 }
086 }
087
088 /**
089 * Set the enabled state of LiveWindow. If it's being enabled, turn off the
090 * scheduler and remove all the commands from the queue and enable all the
091 * components registered for LiveWindow. If it's being disabled, stop all
092 * the registered components and reenable the scheduler. TODO: add code to
093 * disable PID loops when enabling LiveWindow. The commands should reenable
094 * the PID loops themselves when they get rescheduled. This prevents arms
095 * from starting to move around, etc. after a period of adjusting them in
096 * LiveWindow mode.
097 */
098 public static void setEnabled(boolean enabled) {
099 if (liveWindowEnabled != enabled) {
100 if (enabled) {
101 System.out.println("Starting live window mode.");
102 if (firstTime) {
103 initializeLiveWindowComponents();
104 firstTime = false;
105 }
106 Scheduler.getInstance().disable();
107 Scheduler.getInstance().removeAll();
108 for (Enumeration e = components.keys(); e.hasMoreElements();) {
109 LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
110 component.startLiveWindowMode();
111 }
112 } else {
113 System.out.println("stopping live window mode.");
114 for (Enumeration e = components.keys(); e.hasMoreElements();) {
115 LiveWindowSendable component = (LiveWindowSendable) e.nextElement();
116 component.stopLiveWindowMode();
117 }
118 Scheduler.getInstance().enable();
119 }
120 liveWindowEnabled = enabled;
121 statusTable.putBoolean("LW Enabled", enabled);
122 }
123 }
124
125 /**
126 * The run method is called repeatedly to keep the values refreshed on the screen in
127 * test mode.
128 */
129 public static void run() {
130 updateValues();
131 }
132
133 /**
134 * Add a Sensor associated with the subsystem and with call it by the given
135 * name.
136 *
137 * @param subsystem The subsystem this component is part of.
138 * @param name The name of this component.
139 * @param component A LiveWindowSendable component that represents a sensor.
140 */
141 public static void addSensor(String subsystem, String name, LiveWindowSendable component) {
142 components.put(component, new LiveWindowComponent(subsystem, name, true));
143 }
144
145 /**
146 * Add an Actuator associated with the subsystem and with call it by the
147 * given name.
148 *
149 * @param subsystem The subsystem this component is part of.
150 * @param name The name of this component.
151 * @param component A LiveWindowSendable component that represents a
152 * actuator.
153 */
154 public static void addActuator(String subsystem, String name, LiveWindowSendable component) {
155 components.put(component, new LiveWindowComponent(subsystem, name, false));
156 }
157
158 /**
159 * Puts all sensor values on the live window.
160 */
161 private static void updateValues() {
162 //TODO: gross - needs to be sped up
163 for (int i = 0; i < sensors.size(); i++) {
164 LiveWindowSendable lws = (LiveWindowSendable) sensors.elementAt(i);
165 lws.updateTable();
166 }
167 // TODO: Add actuators?
168 // TODO: Add better rate limiting.
169 }
170
171 /**
172 * Add Sensor to LiveWindow. The components are shown with the module type,
173 * slot and channel like this: Gyro[1, 2] for a gyro object connected to the
174 * first analog module in channel 2
175 *
176 * @param moduleType A string indicating the type of the module used in the
177 * naming (above)
178 * @param moduleNumber The number of the particular module type
179 * @param channel The channel number the device is connected to
180 * @param component A reference to the object being added
181 */
182 public static void addSensor(String moduleType, int moduleNumber, int channel, LiveWindowSendable component) {
183 addSensor("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]", component);
184 if (sensors.contains(component)) {
185 sensors.removeElement(component);
186 }
187 sensors.addElement(component);
188 }
189
190 /**
191 * Add Actuator to LiveWindow. The components are shown with the module
192 * type, slot and channel like this: Servo[1,2] for a servo object connected
193 * to the first digital module and PWM port 2.
194 *
195 * @param moduleType A string that defines the module name in the label for
196 * the value
197 * @param moduleNumber The number of the particular module type
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 moduleNumber, int channel, LiveWindowSendable component) {
203 addActuator("Ungrouped", moduleType + "[" + moduleNumber + "," + channel + "]", component);
204 }
205 }