Tekkotsu Homepage | Demos | Overview | Downloads | Dev. Resources | Reference | Credits |
Controller.hGo to the documentation of this file.00001 //-*-c++-*- 00002 #ifndef INCLUDED_Controller_h 00003 #define INCLUDED_Controller_h 00004 00005 #include "Controls/ControlBase.h" 00006 #include "Behaviors/BehaviorBase.h" 00007 #include "Events/EventBase.h" 00008 #include "Events/EventRouter.h" 00009 #include "Motion/MotionManager.h" 00010 #include "Wireless/Wireless.h" 00011 #include "Wireless/Socket.h" 00012 #include <stack> 00013 00014 //! Handles the menu/command system... when it detects the EmergencyStopMC is activated, it'll kick into high priority. 00015 /*! Keeps track of a command stack. A Control can designate another sub-control, which will receive events until it finishes\n 00016 * Events will then be sent to the parent again. 00017 * 00018 * The GUI uses the same commands as the user (makes it much easier to have only one parser). 00019 * The commands are: 00020 * - '<tt>!refresh</tt>' - redisplays the current control (handy on first connecting, or when other output has scrolled it off the screen) 00021 * - '<tt>!reset</tt>' - return to the root control 00022 * - '<tt>!next</tt>' - calls ControlBase::doNextItem() of the current control 00023 * - '<tt>!prev</tt>' - calls ControlBase::doPrevItem() of the current control 00024 * - '<tt>!select</tt> [<i>item</i>]' - calls ControlBase::doSelect() of the current control, unless <i>item</i> is specified, in which case it is searched for, starting at the root. 00025 * - '<tt>!cancel</tt>' - calls current ControlBase::doCancel(), indicates control should cease activity and return to parent (e.g. "Back" button) 00026 * - '<tt>!dump_stack</tt>' - requests a dump of the current stack of submenus (useful if the GUI (re)connects and thus current robot state is unknown) 00027 * - '<tt>!post </tt><i>generator source type</i> [<i>duration</i>]' - posts an event of your choosing; <i>Generator</i> should be an entry in EventBase::EventGeneratorNames (e.g. timerEGID) or numeric value; <i>source</i> should be a numeric value (unless generator is buttonEGID, in which case it could be an entry from #buttonNames); <i>type</i> can be a numeric value, EventBase::EventTypeNames (e.g. <tt>activate</tt>), or EventBase::EventTypeAbbr (e.g. <tt>A</tt>); <i>duration</i>, if specified, gives the value for EventBase::duration 00028 * - '<tt>!msg </tt><i>text</i>' - sends <i>text</i> out as a TextMsgEvent; also note that any text entered on the console port while a GUI is also connected will also be sent as a TextMsgEvent, without needing the !input. 00029 * - '<tt>!root </tt><i>text</i>' - calls ControlBase::takeInput(<i>text</i>) on the root control 00030 * - '<tt>!hello</tt>' - responds with '<tt>hello\\n</tt><i>count</i>\\n' where <i>count</i> is the number of times '<tt>!hello</tt>' has been sent. Good for detecting first connection after boot vs. a reconnect. 00031 * - '<tt>!hilight</tt> [<i>n1</i> [<i>n2</i> [...]]]' - hilights zero, one, or more items in the menu 00032 * - '<tt>!input </tt><i>text</i>' - calls ControlBase::takeInput(text) on the currently hilighted control(s) 00033 * - '<tt>!set </tt><i>section</i><tt>.</tt><i>key</i><tt>=</tt><i>value</i>' - will be sent to Config::setValue(<i>section</i>,<i>key</i>,<i>value</i>) 00034 * - '<tt>!refreshsketchworld</tt>' - refresh world sketch 00035 * - '<tt>!refreshsketchlocal</tt>' - refresh local sketch 00036 * - '<tt>!refreshsketchcamera</tt>' - refresh camera sketch 00037 * - any text not beginning with '<tt>!</tt>' - sent to ControlBase::takeInput() of the current control 00038 * 00039 * In return, to send the menus to the GUI, the following messages are sent: (newlines are required where shown) 00040 * - '<tt>push</tt>' - signals a submenu has been activated 00041 * - '<tt>pop</tt>' - signals a submenu has been closed 00042 * - '<tt>refresh</tt>\n 00043 * <i>text:title</i>\n 00044 * <i>int:numitems</i>\n 00045 * <i>bool:hasSubmenus</i><sub>1</sub>\n 00046 * <i>bool:hilighted</i><sub>1</sub>\n 00047 * <i>text:item-title</i><sub>1</sub>\n 00048 * <i>text:item-description</i><sub>1</sub>\n 00049 * ...\n 00050 * <i>bool:hasSubmenus<sub>numitems</sub></i>\n 00051 * <i>bool:hilighted<sub>numitems</sub></i>\n 00052 * <i>text:item-title<sub>numitems</sub></i>\n 00053 * <i>text:item-description<sub>numitems</sub></i>' - refreshes the current menu\n 00054 * - '<tt>status</tt>\n 00055 * <i>text</i>' - sets the status bar to <i>text</i> (until the next refresh) 00056 * - '<tt>load</tt>\n 00057 * <i>text:classname</i>\n 00058 * <i>text:instancename</i>\n 00059 * <i>int:port</i>\n 00060 * [<i>arg1</i> [<i>arg2</i> [...]]]' - tells the GUI to load the java class named <i>classname</i>, and have it connect to <i>port</i>, passing it the argument list. 00061 * <i>classname</i> should contain a constructor of the form <tt>Classname(String </tt><i>host</i>, <tt>int </tt><i>port</i>, <tt>String </tt><i>args</i><tt>[])</tt> 00062 * the argument list is parsed as if it were on the console - unescaped or unquoted spaces will separate args into elements in the array 00063 * - '<tt>close</tt>\n 00064 * <i>text:instancename</i>' - calls <tt>close()</tt> on an object previously created by a <tt>load</tt> message. 00065 * The Java object is expected to contain a function <tt>void close()</tt>. 00066 * - '<tt>stack_dump</tt>\n 00067 * <i>int:depth</i>\n 00068 * <i>text:item-title</i><sub>1</sub>\n 00069 * ...\n 00070 * <i>text:item-title</i><sub>depth</sub>' - a listing of the current stack, first item is root, last item is current control 00071 * - '<tt>goodbye</tt>' - Indicates the connection is about to be closed purposefully, to differentiate from an accidental cut off. 00072 * 00073 * bool types are expected to be numerical values, 0 for false, 00074 * non-zero for true. 00075 * 00076 * <tt>load</tt> and <tt>close</tt> are intended to allow pop-up 00077 * windows for custom displays. 00078 * 00079 * The upstream is the responsibility of the individual Controls, but 00080 * the protocol is listed here to keep it together. When a control's 00081 * state changes, it's that control's responsiblity to refresh the UI 00082 * (LEDs, console, and GUI as appropriate). Thus, future extensions 00083 * to the upstream protocol are between the control which will use it 00084 * and the GUI. Future extensions to the downstream protocol would 00085 * involve changing Controller and the GUI. 00086 * 00087 * The Controller may connect to serr in the future to pop-up an alert 00088 * anytime output to serr occurs. 00089 * 00090 * Note that all state is maintained on the robot - even if the GUI 00091 * is connected, you can still use the buttons to interact with the 00092 * controller, and the GUI will update to reflect the changes. In 00093 * HCI (Human Computer Interaction) parlance, this is the MVC, 00094 * Model-View-Controller architecture, almost by necessity. (HCI 00095 * happens to be my double major when I was an undergrad ;) 00096 * 00097 * Also, the Controller is responsible for sending out TextMsgEvents 00098 * from user input it receives - either a !msg command from the 00099 * console or GUI, or <i>any text at all</i> which is received on the 00100 * console if there is already a GUI connected. 00101 * 00102 * These TextMsgEvents are always status events, and the duration 00103 * field is always 0. 00104 */ 00105 class Controller : public BehaviorBase, public EventTrapper { 00106 public: 00107 Controller() : BehaviorBase("Controller"), EventTrapper(), display(MotionManager::invalid_MC_ID), estop_id(MotionManager::invalid_MC_ID), root(NULL), cmdstack(), last_time(0), cur_time(0), nextEv_val(0), nextEv_dur(0), prevEv_val(0), prevEv_dur(0), alreadyGotBoth(false), isControlling(false), usesButtons(false), gui_comm(NULL) {init();} //!< Constructor 00108 Controller(ControlBase* r) : BehaviorBase("Controller"), EventTrapper(), display(MotionManager::invalid_MC_ID), estop_id(MotionManager::invalid_MC_ID), root(r), cmdstack(), last_time(0), cur_time(0), nextEv_val(0), nextEv_dur(0), prevEv_val(0), prevEv_dur(0), alreadyGotBoth(false), isControlling(false), usesButtons(false), gui_comm(NULL) { init(); } //!< Constructor, sets a default root control 00109 virtual ~Controller() { 00110 delete root; 00111 theOneController=NULL; 00112 } //!< Destructor 00113 00114 //@{ 00115 //! event masks used by processEvent() 00116 static EventBase nextItem; 00117 static EventBase prevItem; 00118 static EventBase nextItemFast; 00119 static EventBase prevItemFast; 00120 static EventBase selectItem; 00121 static EventBase cancel; //@} 00122 00123 virtual void doStart(); //!< register for events and resets the cmdstack 00124 virtual void doStop(); //!< stop listening for events and resets the cmdstack 00125 virtual void doEvent(); //!< just for e-stop activation/deactivation 00126 virtual bool trapEvent(const EventBase& e); //!< passes an event to the top control 00127 00128 void reset(); //!< will take the command stack back down to the root 00129 void refresh(); //!< refreshes the display, for times like sub-control dying, the previous control needs to reset it's display 00130 00131 void refreshSketchWorld(); //!< refresh world sketches 00132 void refreshSketchLocal(); //!< refresh local sketches 00133 void refreshSketchCamera(); //!< refresh camera sketches 00134 00135 void push(ControlBase* c); //!< puts a new control on top 00136 void pop(); //!< kills the top control, goes to previous 00137 ControlBase* top() { return cmdstack.top(); } //!< returns the current control 00138 00139 Controller& setRoot(ControlBase* r); //!< sets the root level control 00140 00141 Controller& setEStopID(MotionManager::MC_ID estopid); //!< Sets the emergency stop MC to monitor for pausing 00142 00143 static std::string getClassDescription() { return "Provides interface for activating/deactivating controls (and through them, behaviors)"; } 00144 virtual std::string getDescription() const { return getClassDescription(); } 00145 00146 00147 static void loadGUI(const std::string& type, const std::string& name, unsigned int port) {loadGUI(type,name,port,std::vector<std::string>());} //!< attempts to open a Java object on the desktop 00148 static void loadGUI(const std::string& type, const std::string& name, unsigned int port, const std::vector<std::string>& args); //!< attempts to open a Java object on the desktop 00149 static void closeGUI(const std::string& name); //!< calls close() on a Java object loaded with loadGUI() (on the desktop) 00150 00151 static int gui_comm_callback(char *buf, int bytes); //!< called by wireless when there's new data from the GUI 00152 static int console_callback(char *buf, int bytes); //!< called by wireless when someone has entered new data on the tekkotsu console (NOT cin) 00153 00154 protected: 00155 //! calls initButtons with the appropriate button offsets for the host robot model 00156 void init(); 00157 00158 //! assigns appropriate values to the static event bases 00159 void initButtons(unsigned fastTime, unsigned downTime, unsigned nextB, unsigned prevB, unsigned nextFastB, unsigned prevFastB, unsigned selectB, unsigned cancelB); 00160 00161 //! called with each line that's entered on the tekkotsu console or from the GUI 00162 void takeLine(const std::string& s); 00163 00164 //! sends stack of currently active controls 00165 void dumpStack(); 00166 00167 //! called with slots (options), a name to lookup; will select the named control 00168 bool select(ControlBase* item, const std::string& name); 00169 00170 //! sets a config value - some values may require additional processing (done here) to have the new values take effect 00171 int setConfig(const std::string& str); 00172 00173 //! maintains top Control 00174 /*! @param next one of: @li NULL: pop() ::cmdstack @li ::cmdstack.top(): nothing @li other address: ::push(@a next) 00175 * @return true, all the time, for convenience from trapEvent() */ 00176 bool setNext(ControlBase* next); 00177 00178 //! called when the estop switches on 00179 /*! causes the top control to activate, registers for button events */ 00180 void activate(); 00181 00182 //! called when the estop switches off\n 00183 /*! causes the top control to deactivate, stops listening for buttons */ 00184 void deactivate(); 00185 00186 //! @brief returns true if a valid control is available on the stack 00187 /*! if the stack is empty, will push root if it's non-null */ 00188 bool chkCmdStack(); 00189 00190 //! invalid_MC_ID if not active, otherwise id of high priority LEDs 00191 MotionManager::MC_ID display; 00192 00193 //! the EmergencyStopMC MC_ID that this Controller is monitoring 00194 MotionManager::MC_ID estop_id; 00195 00196 //! the base control, if cmdstack underflows, it will be reset to this 00197 ControlBase * root; 00198 00199 /*! @brief the stack of the current control hierarchy\n 00200 * should never contain NULL entries */ 00201 std::stack< ControlBase* > cmdstack; 00202 00203 //! returns true when the current time and last time are in different periods 00204 static bool calcPulse(unsigned int t, unsigned int last, unsigned int period) { 00205 if(period<t-last) 00206 return true; 00207 bool nextclock=(t/period)&1; 00208 bool lastclock=(last/period)&1; 00209 return (lastclock!=nextclock); 00210 } 00211 00212 00213 unsigned int last_time; //!< the time of the last event 00214 unsigned int cur_time; //!< the time of the current event (do*() can check this instead of calling get_time() ) 00215 float nextEv_val; //!< the magnitude of the last next event (::nextItem) 00216 unsigned int nextEv_dur; //!< the duration of the last next event (::nextItem) 00217 float prevEv_val; //!< the magnitude of the last prev event (::prevItem) 00218 unsigned int prevEv_dur; //!< the duration of the last prev event (::prevItem) 00219 bool alreadyGotBoth; //!< if doReadStdIn() was already called, but the buttons are both still down 00220 bool isControlling; //!< true if the Controller is currently active (in the activate()/deactivate() sense, not doStart()/doStop() sense - use isActive() for that...) 00221 bool usesButtons; //!< true if ControllerGUI knows how to use the buttons for menu navigation, will intercept button presses 00222 00223 Socket * gui_comm; //!< the socket to listen on for the gui 00224 public: 00225 static Controller * theOneController; //!< currently can't pull connection socket off of server socket, so only one Controller 00226 00227 private: 00228 Controller(const Controller&); //!< shouldn't be called... 00229 Controller& operator=(const Controller&); //!< shouldn't be called... 00230 }; 00231 00232 /*! @file 00233 * @brief Describes Controller class, a behavior that should be started whenever the emergency stop goes on to provide menus for robot control 00234 * @author ejt (Creator) 00235 */ 00236 00237 #endif |
Tekkotsu v5.1CVS |
Generated Mon May 9 04:58:37 2016 by Doxygen 1.6.3 |