source: pacpusframework/trunk/include/Pacpus/kernel/InputOutputInterface.h@ 269

Last change on this file since 269 was 269, checked in by Marek Kurdej, 10 years ago

Major: InputOutputInterface callback method with 1 or 2 arguments: 1st can be const or non-const, second (PacpusEvent) can be optional.

  • Property svn:executable set to *
File size: 7.4 KB
Line 
1#ifndef IN_OUT_INTERFACE_H
2#define IN_OUT_INTERFACE_H
3
4#include <Pacpus/kernel/InputOutputBase.h>
5#include <Pacpus/kernel/Log.h>
6
7#include <QByteArray>
8#include <QCoreApplication>
9#include <typeinfo>
10
11namespace pacpus {
12
13template <typename T, class C>
14class InputInterface
15 : public InputInterfaceBase
16{
17public:
18 typedef T data_type;
19 typedef C component_type;
20 typedef void (C::*process_data_function_type_with_event)(T&, PacpusEvent);
21 typedef void (C::*process_data_function_type)(T&);
22 typedef void (C::*process_const_data_function_type_with_event)(T const&, PacpusEvent);
23 typedef void (C::*process_const_data_function_type)(T const&);
24
25 InputInterface(QString name, C* component, process_data_function_type_with_event processingMethod)
26 : InputInterfaceBase(name, component, component)
27 {
28 mProcessingMethod.fe = processingMethod;
29 }
30
31 InputInterface(QString name, C* component, process_data_function_type processingMethod)
32 : InputInterfaceBase(name, component, component)
33 {
34 mProcessingMethod.f = processingMethod;
35 }
36
37 InputInterface(QString name, C* component, process_const_data_function_type_with_event processingMethod)
38 : InputInterfaceBase(name, component, component)
39 {
40 mProcessingMethod.cfe = processingMethod;
41 }
42
43 InputInterface(QString name, C* component, process_const_data_function_type processingMethod)
44 : InputInterfaceBase(name, component, component)
45 {
46 mProcessingMethod.cf = processingMethod;
47 }
48
49 ~InputInterface()
50 {
51 }
52
53 std::size_t getDataSize() const
54 {
55 return sizeof(T);
56 }
57
58 std::type_info const& getDataType() const
59 {
60 return typeid(T);
61 }
62
63 // FIXME: what's the purpose of this function?
64 //PacpusEvent * getEventTemplate()
65 //{
66 // return new PacpusTypedEvent<T>(TYPED_EVENT);
67 //}
68
69 // FIXME: what's the purpose of this function?
70 void customEvent(QEvent* event)
71 {
72 static road_timerange_t const kMaximumBoundedTimeRange = 500;
73
74 if (!event) {
75 LOG_WARN("null event");
76 return;
77 }
78
79 // check that component has been started
80 if ((NULL == getComponent()) || (!getComponent()->isActive())) {
81 LOG_DEBUG("component is not active");
82 return;
83 }
84
85 LOG_TRACE("Receiver: " << getSignature());
86
87 //PacpusTypedEvent<T>* typedEvent = dynamic_cast<PacpusTypedEvent<T> *>(event);
88 PacpusEvent* pacpusEvent = dynamic_cast<PacpusEvent*>(event);
89 if (!pacpusEvent) {
90 LOG_WARN("dynamic_cast failed: not a PacpusEvent");
91 return;
92 }
93 PacpusTypedEvent<T>* typedEvent = dynamic_cast<PacpusTypedEvent<T>*>(pacpusEvent);
94 if (!typedEvent) {
95 LOG_WARN("dynamic_cast failed: incompatible event types");
96 return;
97 }
98
99 switch (event->type()) {
100 case TYPED_EVENT:
101 if (TimeBounded == readingMode() && typedEvent->timerange() < kMaximumBoundedTimeRange) {
102 LOG_WARN("Incorrect TimeRange (< " << kMaximumBoundedTimeRange << "), switching to NeverSkip mode");
103 readingMode() = NeverSkip;
104 }
105
106 switch (readingMode()) {
107 case TimeBounded:
108 if (road_time() - typedEvent->time() > typedEvent->timerange()) {
109 LOG_TRACE("Data skipped, receiver: " << this->getSignature());
110 break;
111 }
112
113 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
114 break;
115
116 case GetLast:
117 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
118
119 // delete all remaining events
120 QCoreApplication::removePostedEvents(this, TYPED_EVENT);
121 break;
122
123 case NeverSkip:
124 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
125 break;
126
127 default:
128 LOG_WARN("Unknown reading mode " << readingMode());
129 break;
130 }
131 break;
132
133 // Add here new event type if needed
134
135 default:
136 LOG_WARN("Unknown event ID " << event->type());
137 break;
138 }
139 event->accept();
140 }
141
142 // TODO: pull mode (NOT YET IMPLEMENTED!!!)
143 T& getData()
144 {
145 T data;
146 // TODO: ask the output data;
147 return data;
148 }
149
150protected:
151 struct ProcessingMethod
152 {
153 ProcessingMethod()
154 {
155 fe = NULL;
156 f = NULL;
157 cfe = NULL;
158 cf = NULL;
159 }
160
161 void invoke(ComponentBase* component, T& data, PacpusEvent event)
162 {
163 C* comp = dynamic_cast<C*>(component);
164 if (NULL == comp) {
165 LOG_WARN("NULL component");
166 return;
167 }
168 if (fe) {
169 (comp->*fe)(data, event);
170 } else if (f) {
171 (comp->*f)(data);
172 } else if (cfe) {
173 (comp->*cfe)(data, event);
174 } else if (cf) {
175 (comp->*cf)(data);
176 } else {
177 LOG_WARN("no method to invoke");
178 }
179 }
180
181 process_data_function_type_with_event fe;
182 process_data_function_type f;
183 process_const_data_function_type_with_event cfe;
184 process_const_data_function_type cf;
185 };
186
187 ProcessingMethod mProcessingMethod;
188};
189
190template <typename T, class C>
191class OutputInterface
192 : public OutputInterfaceBase
193{
194public:
195 typedef T data_type;
196 typedef C component_type;
197
198 OutputInterface(QString name, C* component)
199 : OutputInterfaceBase(name, component, component)
200 {}
201
202 ~OutputInterface()
203 {}
204
205 /// Send data through a typed output
206 void send(T const& data, road_time_t t = road_time(), road_timerange_t tr = 0);
207
208 std::size_t getDataSize() const
209 {
210 return sizeof(T);
211 }
212
213 std::type_info const& getDataType() const
214 {
215 return typeid(T);
216 }
217};
218
219template <typename T, class C>
220void OutputInterface<T, C>::send(T const& data, road_time_t t, road_timerange_t tr)
221{
222 // FIXME: use shared data
223 //QSharedPointer<T> sharedPointer = new T(data);
224
225 for (QList<ConnectionBase>::iterator it = connections().begin(), itend = connections().end(); it != itend; ++it) {
226 // Qt documentation:
227 // The event must be allocated on the heap since the post event queue will take ownership of the event and delete it once it has been posted.
228 // It is not safe to access the event after it has been posted.
229 QEvent* pacpusEvent = new PacpusTypedEvent<T>(TYPED_EVENT, data, t, tr);
230 QCoreApplication::postEvent(
231 it->getInterface(),
232 pacpusEvent,
233 it->getPriority()
234 );
235 LOG_TRACE("Sender: " << it->getInterface()->getSignature());
236 }
237}
238
239template <typename T1, typename T2, class C>
240bool checkedSend(OutputInterface<T1, C>* sender, T2 const& data, road_time_t t = road_time(), road_timerange_t tr = 0);
241
242template <typename T1, typename T2, class C>
243bool checkedSend(OutputInterface<T1, C>* sender, T2 const& data, road_time_t t, road_timerange_t tr)
244{
245 if (sender && sender->hasConnection()) {
246 sender->send(data, t, tr);
247 return true;
248 }
249 return false;
250}
251
252} // namespace pacpus
253
254#endif // IN_OUT_INTERFACE_H
Note: See TracBrowser for help on using the repository browser.