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
RevLine 
[89]1#ifndef IN_OUT_INTERFACE_H
2#define IN_OUT_INTERFACE_H
3
[199]4#include <Pacpus/kernel/InputOutputBase.h>
[95]5#include <Pacpus/kernel/Log.h>
[199]6
[153]7#include <QByteArray>
[200]8#include <QCoreApplication>
[110]9#include <typeinfo>
[89]10
11namespace pacpus {
12
[152]13template <typename T, class C>
[148]14class InputInterface
15 : public InputInterfaceBase
[89]16{
17public:
[199]18 typedef T data_type;
19 typedef C component_type;
[269]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&);
[199]24
[269]25 InputInterface(QString name, C* component, process_data_function_type_with_event processingMethod)
[152]26 : InputInterfaceBase(name, component, component)
[206]27 {
[269]28 mProcessingMethod.fe = processingMethod;
[206]29 }
[269]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 }
[89]48
[148]49 ~InputInterface()
[206]50 {
51 }
[89]52
[199]53 std::size_t getDataSize() const
[148]54 {
55 return sizeof(T);
56 }
[89]57
[269]58 std::type_info const& getDataType() const
[148]59 {
[199]60 return typeid(T);
[148]61 }
[96]62
[199]63 // FIXME: what's the purpose of this function?
[206]64 //PacpusEvent * getEventTemplate()
65 //{
66 // return new PacpusTypedEvent<T>(TYPED_EVENT);
67 //}
[148]68
[199]69 // FIXME: what's the purpose of this function?
[269]70 void customEvent(QEvent* event)
[148]71 {
[269]72 static road_timerange_t const kMaximumBoundedTimeRange = 500;
73
74 if (!event) {
75 LOG_WARN("null event");
76 return;
77 }
78
[206]79 // check that component has been started
80 if ((NULL == getComponent()) || (!getComponent()->isActive())) {
81 LOG_DEBUG("component is not active");
82 return;
83 }
84
[258]85 LOG_TRACE("Receiver: " << getSignature());
[206]86
[269]87 //PacpusTypedEvent<T>* typedEvent = dynamic_cast<PacpusTypedEvent<T> *>(event);
88 PacpusEvent* pacpusEvent = dynamic_cast<PacpusEvent*>(event);
[206]89 if (!pacpusEvent) {
90 LOG_WARN("dynamic_cast failed: not a PacpusEvent");
91 return;
92 }
[269]93 PacpusTypedEvent<T>* typedEvent = dynamic_cast<PacpusTypedEvent<T>*>(pacpusEvent);
[206]94 if (!typedEvent) {
95 LOG_WARN("dynamic_cast failed: incompatible event types");
96 return;
97 }
98
[89]99 switch (event->type()) {
[148]100 case TYPED_EVENT:
[269]101 if (TimeBounded == readingMode() && typedEvent->timerange() < kMaximumBoundedTimeRange) {
102 LOG_WARN("Incorrect TimeRange (< " << kMaximumBoundedTimeRange << "), switching to NeverSkip mode");
[153]103 readingMode() = NeverSkip;
104 }
[110]105
[148]106 switch (readingMode()) {
[110]107 case TimeBounded:
[148]108 if (road_time() - typedEvent->time() > typedEvent->timerange()) {
[206]109 LOG_TRACE("Data skipped, receiver: " << this->getSignature());
[148]110 break;
111 }
[110]112
[269]113 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
[89]114 break;
[110]115
116 case GetLast:
[269]117 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
118
[153]119 // delete all remaining events
120 QCoreApplication::removePostedEvents(this, TYPED_EVENT);
[110]121 break;
122
123 case NeverSkip:
[269]124 mProcessingMethod.invoke(component(), typedEvent->data(), *typedEvent);
[159]125 break;
[110]126
127 default:
[159]128 LOG_WARN("Unknown reading mode " << readingMode());
[206]129 break;
[89]130 }
[110]131 break;
[89]132
[184]133 // Add here new event type if needed
[89]134
[110]135 default:
[153]136 LOG_WARN("Unknown event ID " << event->type());
[110]137 break;
[89]138 }
[206]139 event->accept();
[110]140 }
[89]141
[269]142 // TODO: pull mode (NOT YET IMPLEMENTED!!!)
143 T& getData()
[206]144 {
[110]145 T data;
[269]146 // TODO: ask the output data;
[110]147 return data;
[89]148 }
149
150protected:
[269]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;
[89]188};
189
[152]190template <typename T, class C>
[185]191class OutputInterface
192 : public OutputInterfaceBase
[89]193{
194public:
[199]195 typedef T data_type;
196 typedef C component_type;
197
[269]198 OutputInterface(QString name, C* component)
[185]199 : OutputInterfaceBase(name, component, component)
[184]200 {}
[89]201
[199]202 ~OutputInterface()
203 {}
204
[206]205 /// Send data through a typed output
[269]206 void send(T const& data, road_time_t t = road_time(), road_timerange_t tr = 0);
[184]207
[199]208 std::size_t getDataSize() const
[148]209 {
210 return sizeof(T);
211 }
212
[269]213 std::type_info const& getDataType() const
[148]214 {
[199]215 return typeid(T);
[148]216 }
[89]217};
218
[185]219template <typename T, class C>
[269]220void OutputInterface<T, C>::send(T const& data, road_time_t t, road_timerange_t tr)
[185]221{
[269]222 // FIXME: use shared data
[185]223 //QSharedPointer<T> sharedPointer = new T(data);
224
[200]225 for (QList<ConnectionBase>::iterator it = connections().begin(), itend = connections().end(); it != itend; ++it) {
[269]226 // Qt documentation:
[202]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.
[269]229 QEvent* pacpusEvent = new PacpusTypedEvent<T>(TYPED_EVENT, data, t, tr);
[206]230 QCoreApplication::postEvent(
231 it->getInterface(),
[269]232 pacpusEvent,
[206]233 it->getPriority()
234 );
[258]235 LOG_TRACE("Sender: " << it->getInterface()->getSignature());
[185]236 }
237}
238
[202]239template <typename T1, typename T2, class C>
[269]240bool checkedSend(OutputInterface<T1, C>* sender, T2 const& data, road_time_t t = road_time(), road_timerange_t tr = 0);
[202]241
242template <typename T1, typename T2, class C>
[269]243bool checkedSend(OutputInterface<T1, C>* sender, T2 const& data, road_time_t t, road_timerange_t tr)
[202]244{
245 if (sender && sender->hasConnection()) {
246 sender->send(data, t, tr);
247 return true;
248 }
249 return false;
250}
251
[89]252} // namespace pacpus
253
254#endif // IN_OUT_INTERFACE_H
Note: See TracBrowser for help on using the repository browser.