| #include "LiveWindow/LiveWindow.h" |
| #include "networktables/NetworkTable.h" |
| #include <algorithm> |
| #include <sstream> |
| |
| LiveWindow* LiveWindow::m_instance = NULL; |
| |
| /** |
| * Get an instance of the LiveWindow main class |
| * This is a singleton to guarantee that there is only a single instance regardless of |
| * how many times GetInstance is called. |
| */ |
| LiveWindow * LiveWindow::GetInstance() |
| { |
| if (m_instance == NULL) |
| { |
| m_instance = new LiveWindow(); |
| } |
| return m_instance; |
| } |
| |
| /** |
| * LiveWindow constructor. |
| * Allocate the necessary tables. |
| */ |
| LiveWindow::LiveWindow() |
| { |
| m_enabled = false; |
| m_liveWindowTable = NetworkTable::GetTable("LiveWindow"); |
| m_statusTable = m_liveWindowTable->GetSubTable("~STATUS~"); |
| m_scheduler = Scheduler::GetInstance(); |
| } |
| |
| /** |
| * Change the enabled status of LiveWindow |
| * If it changes to enabled, start livewindow running otherwise stop it |
| */ |
| void LiveWindow::SetEnabled(bool enabled) |
| { |
| if (m_enabled == enabled) |
| return; |
| if (enabled) |
| { |
| printf("Starting live window mode\n"); |
| if (m_firstTime) |
| { |
| InitializeLiveWindowComponents(); |
| m_firstTime = false; |
| } |
| m_scheduler->SetEnabled(false); |
| m_scheduler->RemoveAll(); |
| for (std::map<LiveWindowSendable *, LiveWindowComponent>::iterator it = |
| m_components.begin(); it != m_components.end(); ++it) |
| { |
| it->first->StartLiveWindowMode(); |
| } |
| } |
| else |
| { |
| printf("Ending LiveWindow mode\n"); |
| for (std::map<LiveWindowSendable *, LiveWindowComponent>::iterator it = |
| m_components.begin(); it != m_components.end(); ++it) |
| { |
| it->first->StopLiveWindowMode(); |
| } |
| m_scheduler->SetEnabled(true); |
| } |
| m_enabled = enabled; |
| m_statusTable->PutBoolean("LW Enabled", m_enabled); |
| } |
| |
| LiveWindow::~LiveWindow() |
| { |
| } |
| |
| /** |
| * Add a Sensor associated with the subsystem and with call it by the given name. |
| * @param subsystem The subsystem this component is part of. |
| * @param name The name of this component. |
| * @param component A LiveWindowSendable component that represents a sensor. |
| */ |
| void LiveWindow::AddSensor(char *subsystem, char *name, |
| LiveWindowSendable *component) |
| { |
| m_components[component].subsystem = subsystem; |
| m_components[component].name = name; |
| m_components[component].isSensor = true; |
| } |
| |
| /** |
| * Add an Actuator associated with the subsystem and with call it by the given name. |
| * @param subsystem The subsystem this component is part of. |
| * @param name The name of this component. |
| * @param component A LiveWindowSendable component that represents a actuator. |
| */ |
| void LiveWindow::AddActuator(char *subsystem, char *name, |
| LiveWindowSendable *component) |
| { |
| m_components[component].subsystem = subsystem; |
| m_components[component].name = name; |
| m_components[component].isSensor = false; |
| } |
| |
| /** |
| * INTERNAL |
| */ |
| void LiveWindow::AddSensor(std::string type, int module, int channel, LiveWindowSendable *component) |
| { |
| std::ostringstream oss; |
| oss << type << "[" << module << "," << channel << "]"; |
| std::string types(oss.str()); |
| char* cc = new char[types.size() + 1]; |
| types.copy(cc, types.size()); |
| cc[types.size()]='\0'; |
| AddSensor("Ungrouped", cc, component); |
| if (std::find(m_sensors.begin(), m_sensors.end(), component) == m_sensors.end()) |
| m_sensors.push_back(component); |
| } |
| |
| /** |
| * INTERNAL |
| */ |
| void LiveWindow::AddActuator(std::string type, int module, int channel, LiveWindowSendable *component) |
| { |
| std::ostringstream oss; |
| oss << type << "[" << module << "," << channel << "]"; |
| std::string types(oss.str()); |
| char* cc = new char[types.size() + 1]; |
| types.copy(cc, types.size()); |
| cc[types.size()]='\0'; |
| AddActuator("Ungrouped", cc, component); |
| } |
| |
| /** |
| * Tell all the sensors to update (send) their values |
| * Actuators are handled through callbacks on their value changing from the |
| * SmartDashboard widgets. |
| */ |
| void LiveWindow::UpdateValues() |
| { |
| for (unsigned int i = 0; i < m_sensors.size(); i++) |
| { |
| m_sensors[i]->UpdateTable(); |
| } |
| } |
| |
| /** |
| * This method is called periodically to cause the sensors to send new values |
| * to the SmartDashboard. |
| */ |
| void LiveWindow::Run() |
| { |
| if (m_enabled) |
| { |
| UpdateValues(); |
| } |
| } |
| |
| /** |
| * Initialize all the LiveWindow elements the first time we enter LiveWindow mode. |
| * By holding off creating the NetworkTable entries, it allows them to be redefined |
| * before the first time in LiveWindow mode. This allows default sensor and actuator |
| * values to be created that are replaced with the custom names from users calling |
| * addActuator and addSensor. |
| */ |
| void LiveWindow::InitializeLiveWindowComponents() |
| { |
| for (std::map<LiveWindowSendable *, LiveWindowComponent>::iterator it = |
| m_components.begin(); it != m_components.end(); ++it) |
| { |
| LiveWindowSendable *component = it->first; |
| LiveWindowComponent c = it->second; |
| std::string subsystem = c.subsystem; |
| std::string name = c.name; |
| m_liveWindowTable->GetSubTable(subsystem)->PutString("~TYPE~", |
| "LW Subsystem"); |
| ITable *table = m_liveWindowTable->GetSubTable(subsystem)->GetSubTable( |
| name); |
| table->PutString("~TYPE~", component->GetSmartDashboardType()); |
| table->PutString("Name", name); |
| table->PutString("Subsystem", subsystem); |
| component->InitTable(table); |
| if (c.isSensor) |
| { |
| m_sensors.push_back(component); |
| } |
| } |
| } |
| |