appkit  1.5.1
RoadNarrows Robotics Application Kit
State.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 //
3 // Package: RoadNarrows Robotics Application Tool Kit
4 //
5 // Library: librnr_appkit
6 //
7 // File: State.cxx
8 //
9 /*! \file
10  *
11  * $LastChangedDate: 2013-05-03 07:45:13 -0600 (Fri, 03 May 2013) $
12  * $Rev: 2904 $
13  *
14  * \brief State base class implementation.
15  *
16  * \author Robin Knight (robin.knight@roadnarrows.com)
17  * \author Daniel Packard (daniel@roadnarrows.com)
18  *
19  * \par Copyright
20  * \h_copy 2012-2017. RoadNarrows LLC.\n
21  * http://www.roadnarrows.com\n
22  * All Rights Reserved
23  */
24 /*
25  * @EulaBegin@
26  *
27  * Permission is hereby granted, without written agreement and without
28  * license or royalty fees, to use, copy, modify, and distribute this
29  * software and its documentation for any purpose, provided that
30  * (1) The above copyright notice and the following two paragraphs
31  * appear in all copies of the source code and (2) redistributions
32  * including binaries reproduces these notices in the supporting
33  * documentation. Substantial modifications to this software may be
34  * copyrighted by their authors and need not follow the licensing terms
35  * described here, provided that the new terms are clearly indicated in
36  * all files where they apply.
37  *
38  * IN NO EVENT SHALL THE AUTHOR, ROADNARROWS LLC, OR ANY MEMBERS/EMPLOYEES
39  * OF ROADNARROW LLC OR DISTRIBUTORS OF THIS SOFTWARE BE LIABLE TO ANY
40  * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
41  * DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
42  * EVEN IF THE AUTHORS OR ANY OF THE ABOVE PARTIES HAVE BEEN ADVISED OF
43  * THE POSSIBILITY OF SUCH DAMAGE.
44  *
45  * THE AUTHOR AND ROADNARROWS LLC SPECIFICALLY DISCLAIM ANY WARRANTIES,
46  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
47  * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN
48  * "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO
49  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
50  *
51  * @EulaEnd@
52  */
53 ////////////////////////////////////////////////////////////////////////////////
54 
55 #include <stdio.h>
56 #include <stdarg.h>
57 #include <libgen.h>
58 
59 #include <sstream>
60 #include <string>
61 #include <map>
62 
63 #include "rnr/rnrconfig.h"
64 #include "rnr/log.h"
65 
66 #include "rnr/appkit/Random.h"
67 #include "rnr/appkit/State.h"
68 
69 using namespace std;
70 using namespace rnr;
71 
72 //------------------------------------------------------------------------------
73 // StateEvent Class
74 //------------------------------------------------------------------------------
75 
76 StateEvent::StateEvent(int nEventId,
77  const string &strEventName,
78  const string &strActionName)
79 {
80  m_nEventId = nEventId;
81 
82  if( strEventName.empty() )
83  {
84  stringstream ss;
85 
86  ss << "e" << m_nEventId;
87  ss >> m_strEventName;
88  }
89  else
90  {
91  m_strEventName = strEventName;
92  }
93 
94  if( strActionName.empty() )
95  {
96  stringstream ss;
97 
98  ss << "action_" << m_strEventName;
99  ss >> m_strActionName;
100  }
101  else
102  {
103  m_strActionName = strActionName;
104  }
105 }
106 
107 int StateEvent::execAction(State *pState,
108  int nPrevStateId,
109  int nEventId)
110 {
111  return pState->m_nStateId;
112 }
113 
114 
115 //------------------------------------------------------------------------------
116 // State Class
117 //------------------------------------------------------------------------------
118 
119 State::State(int nStateId,
120  const string &strStateName,
121  const string &strRefTag,
122  StateEvent *listStateEvents[])
123 {
124  int i;
125 
126  init(nStateId, strStateName, strRefTag);
127 
128  for(i=0; listStateEvents[i] != NULL; ++i)
129  {
130  addStateEvent(listStateEvents[i]);
131  }
132 }
133 
134 State::~State()
135 {
136  TransTblMap_T::iterator iter;
137 
138  for(iter=m_mapTransTbl.begin(); iter!=m_mapTransTbl.end(); ++iter)
139  {
140  delete iter->second;
141  }
142  m_mapTransTbl.clear();
143 }
144 
145 int State::addStateEvents(StateEvent *pStateEvent, ...)
146 {
147  va_list ap;
148  int i;
149 
150  va_start(ap, pStateEvent);
151 
152  for(i=0; pStateEvent != NULL; pStateEvent = va_arg(ap, StateEvent *), ++i)
153  {
154  addStateEvent(pStateEvent);
155  }
156 
157  va_end(ap);
158 
159  return i;
160 }
161 
162 void State::addStateEvent(StateEvent *pStateEvent)
163 {
164  TransTblMap_T::iterator pos;
165 
166  if( pStateEvent != NULL )
167  {
168  if( (pos = m_mapTransTbl.find(pStateEvent->getEventId()))
169  != m_mapTransTbl.end() )
170  {
171  LOGWARN("%s: Event %s.%d already exists - replacing.",
172  m_strStateName.c_str(),
173  pos->second->getEventName().c_str(), pos->second->getEventId());
174  delete pos->second;
175  m_mapTransTbl.erase(pos);
176  }
177 
178  m_mapTransTbl[pStateEvent->getEventId()] = pStateEvent;
179 
180  LOGDIAG3("%s: %s.%d state event added.",
181  m_strStateName.c_str(),
182  pStateEvent->getEventName().c_str(), pStateEvent->getEventId());
183  }
184 }
185 
186 bool State::deleteStateEvent(int nEventId)
187 {
188  TransTblMap_T::iterator pos;
189 
190  if( (pos = m_mapTransTbl.find(nEventId)) != m_mapTransTbl.end() )
191  {
192  delete pos->second;
193  m_mapTransTbl.erase(pos);
194  return true;
195  }
196  else
197  {
198  LOGERROR("%s: No event found in transition table with id=%d.",
199  m_strStateName.c_str(), nEventId);
200  return false;
201  }
202 }
203 
204 int State::receiveEvent()
205 {
206  if( m_mapTransTbl.size() > 0 )
207  {
208  TransTblMap_T::iterator pos;
209  Random rand;
210  int i;
211 
212  i = rand.randrange(0, (int)m_mapTransTbl.size()-1);
213 
214  // no '+' or '+=' operator - so crawl through map
215  for(pos = m_mapTransTbl.begin(); i > 0; --i, ++pos);
216 
217  return pos->second->getEventId();
218  }
219  else
220  {
221  return 0;
222  }
223 }
224 
225 int State::dispatchEvent(int nPrevStateId, int nEventId)
226 {
227  TransTblMap_T::iterator pos;
228  StateEvent *pEvent;
229  int nNextStateId;
230 
231  //
232  // Find event in transition table and execute.
233  //
234  if( (pos = m_mapTransTbl.find(nEventId)) != m_mapTransTbl.end() )
235  {
236  pEvent = pos->second;
237 
238  // evaluate guard expression
239  if( pEvent->evalGuardExpr(this, nPrevStateId, nEventId) )
240  {
241  // execute action
242  nNextStateId = pEvent->execAction(this, nPrevStateId, nEventId);
243  }
244 
245  // evaluated to false
246  else
247  {
248  nNextStateId = m_nStateId;
249  }
250  }
251 
252  //
253  // No event in transition table, so execute default action.
254  //
255  else
256  {
257  nNextStateId = actionDefault(nPrevStateId, nEventId);
258  }
259 
260  // stay is this state
261  if( nNextStateId == StateIdThis )
262  {
263  nNextStateId = m_nStateId;
264  }
265 
266  return nNextStateId;
267 }
268 
269 string State::getEventName(int nEventId)
270 {
271  TransTblMap_T::iterator pos;
272 
273  if( (pos = m_mapTransTbl.find(nEventId)) != m_mapTransTbl.end() )
274  {
275  return pos->second->getEventName();
276  }
277  else
278  {
279  return "";
280  }
281 }
282 
283 string State::getActionName(int nEventId)
284 {
285  TransTblMap_T::iterator pos;
286 
287  if( (pos = m_mapTransTbl.find(nEventId)) != m_mapTransTbl.end() )
288  {
289  return pos->second->getActionName();
290  }
291  else
292  {
293  return "";
294  }
295 }
296 
297 
298 void State::printState(FILE *fp, int indent)
299 {
300  TransTblMap_T::iterator iter;
301  StateEvent *pEvent;
302 
303  fprintf(fp, "%*sState: %s.%d\n",
304  indent, "", m_strStateName.c_str(), m_nStateId);
305 
306  for(iter = m_mapTransTbl.begin();
307  iter != m_mapTransTbl.end();
308  ++iter )
309  {
310  pEvent = iter->second;
311  fprintf(fp, "%*sEvent: %s.%d %s\n",
312  indent+2, "",
313  pEvent->getEventName().c_str(), pEvent->getEventId(),
314  pEvent->getActionName().c_str());
315  }
316 }
317 
318 void State::init(int nStateId,
319  const string &strStateName,
320  const string &strRefTag)
321 
322 {
323  m_nStateId = nStateId;
324  m_bHasQueuedEvent = false;
325  m_usecTimeOut = 0;
326 
327  if( strStateName.empty() )
328  {
329  stringstream ss;
330 
331  ss << "S" << m_nStateId;
332  ss >> m_strStateName;
333  }
334  else
335  {
336  m_strStateName = strStateName;
337  }
338 
339  if( strRefTag.empty() )
340  {
341  stringstream ss;
342 
343  ss << m_nStateId;
344  ss >> m_strRefTag;
345  }
346  else
347  {
348  m_strRefTag = strRefTag;
349  }
350 }
351 
352 string State::getReservedStateName(int nStateId)
353 {
354  switch( nStateId )
355  {
356  case StateIdStart:
357  return "*Start";
358  case StateIdPrev:
359  return "Previous"; // if recording, then ...
360  case StateIdThis:
361  return m_strStateName;
362  case StateIdTerminate:
363  return "Terminate*";
364  case StateIdUndef:
365  return "#undef";
366  default:
367  return "";
368  }
369 }
osManipIndent indent()
Left indent at current stream indentation level.
Definition: IOManip.cxx:115
virtual int execAction(State *pState, int nPrevStateId, int nEventId)
Execute action associated with the event.
Definition: State.cxx:107
virtual bool evalGuardExpr(State *pState, int nPrevStateId, int nEventId)
Evaluate event guard condition.
Definition: State.h:109
int randrange(int nMin=0, int nMax=INT_MAX)
Generates a random integer uniformally distrubuted between [nMin, nMax].
Definition: Random.cxx:88
Random variable generator class interface.
Random variable generators class.
Definition: Random.h:79
int m_nStateId
state id
Definition: State.h:389
State base class interface.
RoadNarrows Robotics.
Definition: Camera.h:74