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