Main Page · Modules · All Classes · Class Hierarchy
MAController.cpp
1 /*
2  * This file is part of the AiBO+ project
3  *
4  * Copyright (C) 2005-2016 Csaba Kertész (csaba.kertesz@gmail.com)
5  *
6  * AiBO+ is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * AiBO+ is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
19  *
20  */
21 
22 #include "MAController.hpp"
23 
24 #include "core/MADevice.hpp"
25 #include "core/MAValueGenerators.hpp"
26 #include "types/MARobotState.hpp"
27 #include "types/skits/MASkit.hpp"
28 #include "types/skits/MASkitDatabase.hpp"
29 #include "behaviors/MABehaviorManager.hpp"
30 
31 #include <MCLog.hpp>
32 #include <MCThreadLocalData.hpp>
33 
34 #include <boost/algorithm/string/predicate.hpp>
35 #include <boost/algorithm/string.hpp>
36 
37 #include <algorithm>
38 #include <stdio.h>
39 
40 namespace
41 {
42 // Device pointer-int map
43 typedef boost::unordered_map<MADevice*, int> DevicePtrIntMap;
44 
45 // Verbose mode
46 MCThreadLocalData<bool> Verbose(true);
47 // Reference counter for controllers
48 MCThreadLocalData<int> ControllerRef(true);
49 
50 void CheckStaticControllerVariables()
51 {
52  if (unlikely(!Verbose.get()))
53  {
54  Verbose.reset(new bool);
55  *Verbose = false;
56  ControllerRef.reset(new int);
57  *ControllerRef = 0;
58  }
59 }
60 }
61 
62 MAController::MAController(MA::ControllerType controller_type) : MARobotStateUpdater(MA::UpdateSensorData),
63  MA_CALL_CONTAINER_LOCKER_CTOR, Type(controller_type)
64 {
66 
67  RegisterUpdater(*this);
68  CheckStaticControllerVariables();
69  (*ControllerRef)++;
70  if (*ControllerRef == 1)
71  {
72  new MARobotState(true, true);
73  }
74 }
75 
76 
77 MAController::~MAController()
78 {
79  (*ControllerRef)--;
80  if (*ControllerRef == 0)
81  delete MA::RobotState.release();
82 }
83 
84 
85 MC::StringList MAController::GetTransitionNames() const
86 {
87  MC::StringList TransitionList;
88 
89  for (auto& transition : Transitions)
90  {
91  TransitionList.push_back(transition.first);
92  }
93  return TransitionList;
94 }
95 
96 
98 {
99  MC::StringList TransitionList;
100 
101  for (auto& transition : Transitions)
102  {
103  const MA::DeviceGeneratorsMap& DeviceGenerators = transition.second.get<2>();
104 
105  for (auto& generator : DeviceGenerators)
106  {
107  if (generator.first == &device)
108  {
109  TransitionList.push_back(transition.first);
110  }
111  }
112  }
113  return TransitionList;
114 }
115 
116 
117 int MAController::StartTransition(const std::string& name)
118 {
119  std::string Name(name);
120  std::string RealSkitName;
121  float Scale = 1.0;
122  unsigned int InitialMovementDuration = 0;
123 
124  if (boost::starts_with(Name, MA::SkitNamePrefix))
125  {
126  std::vector<std::string> NameSlices;
127 
128  boost::split(NameSlices, Name, boost::is_any_of(":"));
129  if (NameSlices.size() <= 1)
130  {
131  MC_WARNING("Invalid transition name was requested to start: %s", name.c_str());
132  return -1;
133  }
134  Name = NameSlices[0]+':'+NameSlices[1];
135  RealSkitName = NameSlices[1];
136  // Get the scale factor
137  if (NameSlices.size() >= 3 && !NameSlices[2].empty())
138  Scale = MCStrConvert<float>(NameSlices[2]);
139  // Get the initial movement duration
140  if (NameSlices.size() >= 4 && !NameSlices[3].empty())
141  InitialMovementDuration = MCStrConvert<unsigned int>(NameSlices[3]);
142  }
143  // Identify the transition
144  auto Iter = Transitions.find(Name);
145 
146  if (unlikely(Iter == Transitions.end()))
147  {
148  Iter = RegisterSkitTransition(Name);
149  if (unlikely(Iter == Transitions.end()))
150  {
151  MC_WARNING("Unregistered transition name was requested to start: %s", Name.c_str());
152  return -1;
153  }
154  }
155  if (*Verbose)
156  {
157  MC_LOG("Start transition: %s", Name.c_str());
158  }
159  MA::DeviceGeneratorsMap& DeviceGenerators = Iter->second.get<2>();
160  int InitialMapSize = DeviceGenerators.size();
161  MA::DeviceGeneratorsMap NewDeviceGenerators;
162 
163  if (boost::starts_with(Name, MA::SkitNamePrefix))
164  {
165  // Start a skit transition
166  if (!MA::SkitDatabase.get())
167  {
168  MC_WARNING("Skit database is missing to start a skit transition (%s)", Name.c_str());
169  return -1;
170  }
171  MA::SkitSPtr Skit = MA::SkitDatabase->GetSkit(RealSkitName);
172 
173  if (Skit.get())
174  {
175  if (Type == MA::MotorController)
176  {
177  MA::MotionSkitSPtr MotionSkit = Skit->GetMotionSkit();
178 
179  if (!MotionSkit.get())
180  {
181  MC_WARNING("Skit (%s) does not contain any motion transition", Name.c_str());
182  return -1;
183  }
184  NewDeviceGenerators = GetSkitTransitionGenerators(MotionSkit);
185  } else
186  if (Type == MA::LedController)
187  {
188  MA::LedSkitSPtr LedSkit = Skit->GetLedSkit();
189 
190  if (!LedSkit.get())
191  {
192  MC_WARNING("Skit (%s) does not contain any LED transition", Name.c_str());
193  return -1;
194  }
195  NewDeviceGenerators = GetSkitTransitionGenerators(LedSkit);
196  }
197  } else {
198  MC_WARNING("Skit (%s) is not in the database to start a transition", Name.c_str());
199  return -1;
200  }
201  // Scale the generators if needs be
202  if (Scale > 0 && Scale != 1.0)
203  {
204  for (auto& generator : NewDeviceGenerators)
205  generator.second->ScaleDuration(Scale);
206  }
207  // Add initial movements
208  if (InitialMovementDuration > 0)
209  {
210  for (auto& generator : NewDeviceGenerators)
211  {
212  MAGeneratorBase* Generator = nullptr;
213 
214  Generator = new MASimpleGenerator(generator.second->GetDesiredStartingValue(), InitialMovementDuration);
215  generator.second->AddGenerator(*Generator, true);
216  }
217  }
218  } else {
219  // Start a normal transition
220  NewDeviceGenerators = Iter->second.get<0>()();
221  }
223  {
224  // Set a controller and a transition Name for the new generators...
225  for (auto& generator : NewDeviceGenerators)
226  {
227  generator.second->SetTransitionName(Name);
228  MA_SIGNAL_CONNECT(generator.second->ExpiredSignal, MAController::GeneratorContainerExpired);
229  }
230  // ...and merge them.
231  MA_MERGE_DEVICEGENERATORS(DeviceGenerators, NewDeviceGenerators);
232  }
233  if (InitialMapSize == (int)Iter->second.get<2>().size())
234  {
235  MC_WARNING("The transition did not register any generators: %s", Name.c_str());
236  return -1;
237  }
238  return GetDeviceGeneratorsDuration(DeviceGenerators);
239 }
240 
241 
242 void MAController::StopTransition(const std::string& name)
243 {
244  auto Iter = Transitions.find(name);
245 
246  if (unlikely(Iter == Transitions.end()))
247  {
248  Iter = RegisterSkitTransition(name);
249  if (unlikely(Iter == Transitions.end()))
250  {
251  MC_WARNING("Unregistered transition name was requested to stop: %s", name.c_str());
252  return;
253  }
254  }
255  if (*Verbose)
256  {
257  MC_LOG("Stop transition: %s", name.c_str());
258  }
259  MA::DeviceGeneratorsMap& DeviceGenerators = Iter->second.get<2>();
260 
261  if (DeviceGenerators.size() == 0)
262  return;
263 
265  {
266  // Remove the generator containers
267  for (auto& generator : DeviceGenerators)
268  {
269  MADevice* Device = generator.first;
270 
271  if (Device->HasGeneratorContainer(*generator.second))
272  {
273  generator.second->BlockExpiredSignal();
274  Device->DeleteGeneratorContainer(*generator.second);
275  }
276  }
277  // Clear the original container map
278  DeviceGenerators.clear();
279  }
280 }
281 
282 
283 bool MAController::IsTransitionActive(const std::string& name)
284 {
285  auto Iter = Transitions.find(name);
286 
287  if (unlikely(Iter == Transitions.end()))
288  {
289  Iter = RegisterSkitTransition(name);
290  if (unlikely(Iter == Transitions.end()))
291  {
292  MC_WARNING("Unregistered transition name was queried: %s", name.c_str());
293  return false;
294  }
295  }
296  return !Iter->second.get<2>().empty();
297 }
298 
299 
301 {
302  for (auto& transition : Transitions)
303  {
304  if (!transition.second.get<2>().empty())
305  return true;
306  }
307  return false;
308 }
309 
310 
312 {
313  for (auto& transition : Transitions)
314  {
315  if (boost::starts_with(transition.first, MA::SkitNamePrefix) && !transition.second.get<2>().empty())
316  return true;
317  }
318  return false;
319 }
320 
321 
322 bool MAController::IsTransitionSuccessful(const std::string& name)
323 {
324  auto Iter = Transitions.find(name);
325 
326  if (unlikely(Iter == Transitions.end()))
327  {
328  Iter = RegisterSkitTransition(name);
329  if (unlikely(Iter == Transitions.end()))
330  {
331  MC_WARNING("Unregistered transition name was queried: %s", name.c_str());
332  return false;
333  }
334  }
335  MA::DeviceGeneratorsMap& DeviceGenerators = Iter->second.get<2>();
336 
337  if (!DeviceGenerators.empty())
338  {
339  bool Expired = true;
340  MA::GeneratorContainerList ExpiredContainers;
341 
342  // If all the registered generators have only infinite delays then
343  // the transition is finished.
345  for (auto& generator : DeviceGenerators)
346  {
347  // Block the just-expired signal otherwise the iterator is invalidated in
348  // GeneratorContainerExpired() and crash is granted on AIBO.
349  generator.second->BlockExpiredSignal();
350  if (generator.second->IsExpired())
351  {
352  ExpiredContainers.push_back(generator.second);
353  } else {
354  Expired = false;
355  }
356  generator.second->UnblockExpiredSignal();
357  }
358  // Remove the expired containers here
359  for (unsigned int i = 0; i < ExpiredContainers.size(); ++i)
360  {
361  ExpiredContainers[i]->IsExpired();
362  }
363  if (!Expired)
364  {
365  return false;
366  }
367  }
368  // Query the IsSuccessful()-like function if the generators are expired
369  MA::BoolFuncPtr Func = Iter->second.get<1>();
370 
371  if (!Func.empty())
372  {
373  return Func();
374  }
375  return true;
376 }
377 
378 
379 bool MAController::TransitionHasCheck(const std::string& name)
380 {
381  auto Iter = Transitions.find(name);
382 
383  if (unlikely(Iter == Transitions.end()))
384  {
385  Iter = RegisterSkitTransition(name);
386  if (unlikely(Iter == Transitions.end()))
387  {
388  MC_WARNING("Unregistered transition name was queried: %s", name.c_str());
389  return false;
390  }
391  }
392  MA::BoolFuncPtr Func = Iter->second.get<1>();
393 
394  return !Func.empty();
395 }
396 
397 
399 {
400  std::string TransitionName = container.GetTransitionName();
401  auto Iter = Transitions.find(TransitionName);
402 
403  if (unlikely(Iter == Transitions.end()))
404  {
405  Iter = RegisterSkitTransition(TransitionName);
406  if (unlikely(Iter == Transitions.end()))
407  {
408  MC_WARNING("Generator container with unregistered transition name: %s", TransitionName.c_str());
409  return;
410  }
411  }
413  {
414  MA::DeviceGeneratorsMap& DeviceGenerators = Iter->second.get<2>();
415  bool Erasing = false;
416 
417  for (auto gen_iter = DeviceGenerators.begin(); gen_iter != DeviceGenerators.end();)
418  {
419  // Remove the non-existing or expired generator containers
420  // Note: Erasing from multimap while iterating: see http://stackoverflow.com/questions/446205
421  if (gen_iter->second == &container)
422  {
423  Erasing = true;
424  DeviceGenerators.erase(gen_iter++);
425  break;
426  }
427  ++gen_iter;
428  }
429  if (*Verbose && Erasing && DeviceGenerators.empty())
430  {
431  MC_LOG("Finished transition: %s", TransitionName.c_str());
432  }
433  }
434 }
435 
436 
437 MA::TransitionMap::iterator MAController::RegisterSkitTransition(const std::string& skit_name)
438 {
439  if (!boost::starts_with(skit_name, MA::SkitNamePrefix))
440  {
441  return Transitions.end();
442  }
443  return Transitions.insert(std::make_pair(skit_name, MA::TransitionTuple())).first;
444 }
445 
446 
447 int MAController::GetDeviceGeneratorsDuration(MA::DeviceGeneratorsMap& device_generators)
448 {
449  if (device_generators.empty())
450  return 0;
451 
452  DevicePtrIntMap Devices;
453 
454  // Calculate the duration per device
455  for (auto& generator : device_generators)
456  {
457  // This should not be needed, but be on the safe side
458  if (Devices.find(generator.first) == Devices.end())
459  {
460  Devices[generator.first] = 0;
461  }
462  // Note: Somehow this check is needed after experiencing crash with GetDuration()
463  if (generator.first->HasGeneratorContainer(*generator.second))
464  {
465  int Duration = generator.second->GetDuration();
466 
467  // An infinite generator has been found
468  if (Duration < 0)
469  return -1;
470  Devices[generator.first] += Duration;
471  }
472  }
473  // Select the maximal duration
474  int MaxDuration = 0;
475 
476  for (auto& device : Devices)
477  {
478  MaxDuration = MCMax(MaxDuration, device.second);
479  }
480  return MaxDuration;
481 }
482 
483 
484 void MAController::SetVerbose(bool new_state)
485 {
486  CheckStaticControllerVariables();
487  *Verbose = new_state;
488 }
489 
490 
492 {
493  CheckStaticControllerVariables();
494  return *Verbose;
495 }
MAController(MA::ControllerType controller_type)
Class constructor.
bool IsAnyActiveSkitTransition()
Check if any skit transition is active.
static void SetVerbose(bool new_state)
Set the verbosity of the controller domain.
#define MC_WARNING(...)
Warning macro.
Definition: MCLog.hpp:43
#define MA_CALL_CONTAINER_LOCKER_CTOR
Standard call for the MAContainerLocker ctor.
Device class.
Definition: MADevice.hpp:57
static bool IsVerbose()
Get the verbosity of the controller domain.
bool IsTransitionSuccessful(const std::string &name)
Whenever the transition is successful.
MC::StringList GetTransitionNames() const
Get the list of the transition names.
bool IsAnyActiveTransition()
Check if any transition is active.
Simple generator class.
static void RegisterUpdater(MARobotStateUpdater &updater)
Register a robot state updater.
virtual void StopTransition(const std::string &name)
Stop a transition.
bool TransitionHasCheck(const std::string &name)
Test if the transition has a check.
Generator container class.
Robot state updater base class.
MC::StringList GetActiveTransitionsByDevice(const MADevice &device)
Get a transition list by device.
std::string GetTransitionName() const
Get the transition name where the container belongs to.
virtual int StartTransition(const std::string &name)
Start a transition.
Base class for generators.
#define MA_GET_CONTAINER_LOCK_ID(_container)
Register a lock ID for a container.
void GeneratorContainerExpired(MAGeneratorContainer &container)
Slot for the expired generator containers.
bool IsTransitionActive(const std::string &name)
Whenever the transition is still active.
A wrapper class to cover boost::thread_specific_ptr/folly::ThreadLocal API on certain targets...
MA::TransitionMap::iterator RegisterSkitTransition(const std::string &skit_name)
Register a skit transition if it has not been.
const T MCMax(const U &container)
Get the maximal value of a container.
virtual MA::DeviceGeneratorsMap GetSkitTransitionGenerators(MA::SkitBaseSPtr skit)=0
Get skit transition generators.
int GetDeviceGeneratorsDuration(MA::DeviceGeneratorsMap &device_generators)
Get the duration of the device generators.
#define MA_CONTAINER_LOCK(_container)
Lock a container.
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
MA::ControllerType Type
Controller type.
Robot state.
MA::TransitionMap Transitions
The map of the transitions.