Main Page · Modules · All Classes · Class Hierarchy
MSElement.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 "MSElement.hpp"
23 
24 #include "MSContext.hpp"
25 #include "MSData.hpp"
26 #include "MSHeart.hpp"
27 
28 #include <MCDefs.hpp>
29 #include <MCLog.hpp>
30 
31 #include <QMutexLocker>
32 #include <qpointer.h>
33 #include <qthread.h>
34 #include <qtimer.h>
35 
36 static QPointer<MSContext> Context = nullptr;
37 static int ElementIDs = 0;
38 
39 MSElement::MSElement(MS::ElementType element_type, bool dedicated_thread) : QObject(),
40  DedicatedThread(dedicated_thread), CurrentBeat(-1), PlaybackMode(false),
41  CurrentOutputList(), CurrentInputList(), Type(element_type), EmergencyStop(false),
42  Heart(nullptr), TasksExecutionMutex(QMutex::Recursive)
43 {
44  ElementIDs++;
45  ElementID = ElementIDs;
46  MC_LOG("New element: %s (ID: %d, %p) in thread %p", qPrintable(GetClass()),
47  ElementID, this, thread());
48 
49  Context = MSContext::GetInstance();
50  if (Context)
51  {
52  Context->RegisterElement(*this);
53  }
54  InputList.clear();
55  OutputList.clear();
56 }
57 
58 
60 {
61  MC_LOG("Delete element: %s (ID: %d, %p) in thread %p", qPrintable(GetClass()),
62  ElementID, this, thread());
63  // Clear the fed elements mapping
64  ReceiverElements.clear();
65  if (Context)
66  {
67  Context->UnregisterElement(*this);
68  // Reset the element ID numbering when all elements are unregistered
69  if (!Context->HasRegisteredElements())
70  {
71  ElementIDs = 0;
72  }
73  }
74 }
75 
76 
78 {
79  return DedicatedThread;
80 }
81 
82 
84 {
85  return ElementID;
86 }
87 
88 
89 void MSElement::SetElementID(int new_id)
90 {
91  ElementID = new_id;
92 }
93 
94 
96 {
97  return CurrentBeat;
98 }
99 
100 
101 MS::ElementType MSElement::GetType() const
102 {
103  return Type;
104 }
105 
106 
107 QString MSElement::GetClass() const
108 {
109  return QString(metaObject()->className());
110 }
111 
112 
113 void MSElement::BeatBegin(int beat_id)
114 {
115  // Set the current beat ID
116  CurrentBeat = beat_id;
117  // Clear the output data list
118  CurrentOutputList.clear();
119  // Start the data processing
120  if ((Type != MS::Source) || (!PlaybackMode && Type == MS::Source))
121  {
122  QTimer::singleShot(0, this, SLOT(ProgressIdle()));
123  } else {
124  CurrentInputList.clear();
125  Q_EMIT(BeatEnd(CurrentBeat, this));
126  }
127 }
128 
129 
131 {
132  EmergencyStop = true;
133 }
134 
135 
137 {
138  // Stop the idle if the task is done
139  if (Heart && (EmergencyStop || DoTasks(Heart->GetRemainingBeatTime() <= 10)))
140  {
141  CurrentInputList.clear();
142  Q_EMIT(BeatEnd(CurrentBeat, this));
143  return;
144  } else {
145  QTimer::singleShot(1, this, SLOT(ProgressIdle()));
146  if (!Heart)
147  {
148  Q_EMIT(BeatEnd(CurrentBeat, this));
149  }
150  }
151 }
152 
153 
154 bool MSElement::DoTasks(bool be_hurry)
155 {
156  QMutexLocker Locker(&TasksExecutionMutex);
157 
158  return ProgressTasks(be_hurry);
159 }
160 
161 
163 {
164  // No initialization
165 }
166 
167 
168 bool MSElement::ProgressTasks(bool be_hurry)
169 {
170  Q_UNUSED(be_hurry)
171  // Nothing to do
172  return true;
173 }
174 
175 
177 {
178  // No deinitialization
179 }
180 
181 
182 QStringList MSElement::GetInputList() const
183 {
184  return QStringList(InputList.keys());
185 }
186 
187 
189 {
190  return !OutputList.empty();
191 }
192 
193 
194 QStringList MSElement::GetOutputList() const
195 {
196  return QStringList(OutputList.keys());
197 }
198 
199 
200 void MSElement::AddReceiverElement(const QString& output_name, MSElement& element)
201 {
202  if (output_name.isEmpty())
203  {
204  MC_WARNING("The output name is not specified.");
205  return;
206  }
207  MC_LOG("Add receiver element: %s (%s) -> %s", qPrintable(GetClass()), qPrintable(output_name),
208  qPrintable(element.GetClass()));
209  ReceiverElements.insertMulti(output_name, &element);
210 }
211 
212 
213 void MSElement::RemoveReceiverElement(const QString& output_name, MSElement& element)
214 {
215  if (output_name.isEmpty())
216  {
217  MC_WARNING("The output name is not specified.");
218  return;
219  }
220  for (auto iter = ReceiverElements.begin(); iter != ReceiverElements.end(); ++iter)
221  {
222  if (iter.key() == output_name && iter.value() == &element)
223  {
224  ReceiverElements.erase(iter);
225  break;
226  }
227  }
228 }
229 
230 
231 MSData* MSElement::GetOutputData(const QString& output_name) const
232 {
233  return OutputList[output_name];
234 }
235 
236 
237 void MSElement::SetInputData(const QString& input_name, const MSData& new_data)
238 {
239  if (input_name.isEmpty())
240  {
241  MC_WARNING("The input name is not specified.");
242  return;
243  }
244  if (!InputList.contains(input_name))
245  {
246  MC_WARNING("The input name (%s) is not in the input list.", qPrintable(input_name));
247  return;
248  }
249  CurrentInputList += input_name;
250  *InputList[input_name] = new_data;
251 }
252 
253 
255 {
256  for (auto iter = ReceiverElements.begin(); iter != ReceiverElements.end(); ++iter)
257  {
258  if (CurrentOutputList.contains(iter.key()))
259  {
260  // Avoid the performance hit of this log message with huge
261  // number of data connections
262 // QString Message;
263 //
264 // Message = GetClass()+" (ID"+QString::number((int)GetElementID())+") -> "+
265 // iter.value()->GetClass()+" (ID"+
266 // QString::number((int)iter.value()->GetElementID())+") - "+
267 // iter.key();
268 // MC_LOG( Message.toAscii().data());
269  iter.value()->SetInputData(iter.key(), *OutputList[iter.key()]);
270  }
271  }
272 }
MS::StringDataMap InputList
Input list.
Definition: MSElement.hpp:380
bool DoTasks(bool be_hurry)
Do tasks.
Definition: MSElement.cpp:154
MS::StringElementMap ReceiverElements
Receiver elements.
Definition: MSElement.hpp:370
virtual void StopActivities()
Stop activities.
Definition: MSElement.cpp:176
QString GetClass() const
Get the class name.
Definition: MSElement.cpp:107
void SetElementID(int new_id)
Set the element ID.
Definition: MSElement.cpp:89
QMutex TasksExecutionMutex
Mutex for the element tasks.
Definition: MSElement.hpp:388
void SetInputData(const QString &input_name, const MSData &new_data)
Set an input data of the element.
Definition: MSElement.cpp:237
int GetElementID() const
Get the element ID.
Definition: MSElement.cpp:83
bool PlaybackMode
Playback mode.
Definition: MSElement.hpp:372
bool EmergencyStop
Emergency stop.
Definition: MSElement.hpp:384
MS::StringDataMap OutputList
Output list.
Definition: MSElement.hpp:382
int ElementID
Element ID.
Definition: MSElement.hpp:366
Basic ancestor class of the elements.
Definition: MSElement.hpp:65
#define MC_WARNING(...)
Warning macro.
Definition: MCLog.hpp:43
QStringList CurrentInputList
Specifies the available input data list for the current heart beat.
Definition: MSElement.hpp:376
int GetBeatID() const
Get the current beat ID.
Definition: MSElement.cpp:95
void RemoveReceiverElement(const QString &output_name, MSElement &element)
Remove a receiver element for an output.
Definition: MSElement.cpp:213
void Stop()
Emergency stop.
Definition: MSElement.cpp:130
bool IsDedicatedThread() const
Thread mode of the element.
Definition: MSElement.cpp:77
bool HasOutputs() const
Whenever the element has any outputs.
Definition: MSElement.cpp:188
virtual void StartActivities()
Start activities.
Definition: MSElement.cpp:162
void Feeding()
Feed the interested elements with output data.
Definition: MSElement.cpp:254
void ProgressIdle()
Progress idle.
Definition: MSElement.cpp:136
QStringList GetInputList() const
Get the input list.
Definition: MSElement.cpp:182
QStringList CurrentOutputList
Specifies the available output data for the current heart beat.
Definition: MSElement.hpp:374
void BeatEnd(int beat_id, MSElement *element)
End of a heart beat.
MSElement(MS::ElementType element_type, bool dedicated_thread=false)
Class constructor.
Definition: MSElement.cpp:39
virtual ~MSElement()
Class destructor.
Definition: MSElement.cpp:59
Base class for the data exchange of the elements.
Definition: MSData.hpp:54
void BeatBegin(int beat_id)
Begin of a heart beat.
Definition: MSElement.cpp:113
int CurrentBeat
Current Beat ID.
Definition: MSElement.hpp:368
virtual bool ProgressTasks(bool be_hurry)
Does the task.
Definition: MSElement.cpp:168
bool DedicatedThread
Dedicated thread.
Definition: MSElement.hpp:364
void AddReceiverElement(const QString &output_name, MSElement &element)
Add a receiver element for an output.
Definition: MSElement.cpp:200
MSData * GetOutputData(const QString &output_name) const
Get an output data of the element.
Definition: MSElement.cpp:231
MS::ElementType GetType() const
Get the type of the element.
Definition: MSElement.cpp:101
MSHeart * Heart
Heart where the element is registered.
Definition: MSElement.hpp:386
#define MC_LOG(...)
Debug macro.
Definition: MCLog.hpp:41
QStringList GetOutputList() const
Get the output list.
Definition: MSElement.cpp:194
static MSContext * GetInstance()
Get a static instance of the class.
Definition: MSContext.cpp:268
MS::ElementType Type
Specifies the type of the element.
Definition: MSElement.hpp:378