MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkIGTLMessageProvider.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found in the LICENSE file.
10
11============================================================================*/
12
14
15#include "mitkIGTLDevice.h"
16#include "mitkIGTLMessage.h"
18
19#include "mitkCallbackFromGUIThread.h"
20
21//Microservices
22#include "usServiceReference.h"
23#include "usModuleContext.h"
24#include "usServiceEvent.h"
25#include "mitkServiceInterface.h"
26#include "usGetModuleContext.h"
27
28//igt (remove this later)
29#include "igtlBindMessage.h"
30#include "igtlQuaternionTrackingDataMessage.h"
31#include "igtlTrackingDataMessage.h"
32
33#ifndef WIN32
34#include <unistd.h>
35#endif
36
37namespace mitk
38{
39 itkEventMacroDefinition(StreamingStartRequiredEvent, itk::AnyEvent);
40 itkEventMacroDefinition(StreamingStopRequiredEvent, itk::AnyEvent);
41}
42
45{
46 this->SetName("IGTLMessageProvider");
47 m_IsStreaming = false;
48
49 // Create a command object. The function will be called later from the main thread
50 this->m_StopStreamingCommand = ProviderCommand::New();
51 m_StopStreamingCommand->SetCallbackFunction(this,
53
54 this->m_StreamingCommand = ProviderCommand::New();
55 m_StreamingCommand->SetCallbackFunction(this,
57}
58
60{
61 this->InvokeEvent(StreamingStartRequiredEvent());
62}
63
65{
66
67 Superclass::Update();
68
69 if (this->GetInput() != nullptr)
70 {
71 igtl::MessageBase::Pointer curMessage = this->GetInput()->GetMessage();
72 if (dynamic_cast<igtl::TrackingDataMessage*>(curMessage.GetPointer()) != nullptr)
73 {
74 igtl::TrackingDataMessage* tdMsg =
75 (igtl::TrackingDataMessage*)(curMessage.GetPointer());
76 igtl::TrackingDataElement::Pointer trackingData = igtl::TrackingDataElement::New();
77 tdMsg->GetTrackingDataElement(0, trackingData);
78 float x_pos, y_pos, z_pos;
79 trackingData->GetPosition(&x_pos, &y_pos, &z_pos);
80 }
81 }
82}
83
85{
86 if (this->m_IGTLDevice.IsNull())
87 return;
88
89 for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++)
90 {
91 mitk::IGTLMessage::Pointer msg = const_cast<mitk::IGTLMessage*>(this->GetInput(index));
92 if (msg == nullptr)
93 {
94 continue;
95 }
96
97 if ( !msg->IsDataValid() )
98 {
99 continue;
100 }
101
102 this->m_IGTLDevice->SendMessage(msg);
103 }
104}
105
107{
108 //if outputs are set then delete them
109 if (this->GetNumberOfOutputs() > 0)
110 {
111 for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--)
112 this->RemoveOutput(numOP);
113 this->Modified();
114 }
115
116 //fill the outputs if a valid OpenIGTLink device is set
117 if (m_IGTLDevice.IsNull())
118 return;
119
120 this->SetNumberOfIndexedOutputs(1);
121 if (this->GetOutput(0) == nullptr)
122 {
123 DataObjectPointer newOutput = this->MakeOutput(0);
124 this->SetNthOutput(0, newOutput);
125 this->Modified();
126 }
127}
128
129//void mitk::IGTLMessageProvider::UpdateOutputInformation()
130//{
131// this->Modified(); // make sure that we need to be updated
132// Superclass::UpdateOutputInformation();
133//}
134
135
140
142{
143 //in case the provider is streaming at the moment we have to stop it
144 if (m_IsStreaming)
145 {
146 MITK_DEBUG("IGTLMessageProvider") << "lost connection, stop streaming";
147 this->StopStreamingOfAllSources();
148 }
149}
150
151std::string RemoveRequestPrefixes(std::string requestType)
152{
153 return requestType.substr(4);
154}
155
157{
158 //get the next command
159 igtl::MessageBase::Pointer curCommand = this->m_IGTLDevice->GetNextCommand();
160 //extract the type
161 const char * requestType = curCommand->GetDeviceType();
162 //check the type
163 std::string reqType(requestType);
164 bool isGetMsg = !reqType.find("GET_");
165 bool isSTTMsg = !reqType.find("STT_");
166 bool isSTPMsg = !reqType.find("STP_");
167
168 //get the type from the request type (remove STT_, STP_, GET_, RTS_)
169 std::string type = RemoveRequestPrefixes(requestType);
170 //check all microservices if there is a fitting source for the requested type
171 mitk::IGTLMessageSource::Pointer source = this->GetFittingSource(type.c_str());
172 //if there is no fitting source return a RTS message, if there is a RTS
173 //type defined in the message factory send it
174 if ( source.IsNull() )
175 {
176 if ( !this->GetIGTLDevice()->SendRTSMessage(type.c_str()) )
177 {
178 //sending RTS message failed, probably because the type is not in the
179 //message factory
180 MITK_WARN("IGTLMessageProvider") << "Tried to send a RTS message but did "
181 "not succeed. Check if this type ( "
182 << type << " ) was added to the message "
183 "factory. ";
184 }
185 }
186 else
187 {
188 if ( isGetMsg ) //if it is a single value push it into sending queue
189 {
190 //first it is necessary to update the source. This needs additional time
191 //but is necessary. But are we really allowed to call this here? In which
192 //thread are we? Is the source thread safe?
193 source->Update();
194 mitk::IGTLMessage::Pointer sourceOutput = source->GetOutput();
195 if (sourceOutput.IsNotNull() && sourceOutput->IsDataValid())
196 {
197 if ( source.IsNotNull() )
198 {
199 this->GetIGTLDevice()->SendMessage(sourceOutput);
200 }
201 }
202 }
203 else if ( isSTTMsg )
204 {
205 //read the requested frames per second
206 int fps = 10;
207
208 //read the fps from the command
209 igtl::MessageBase* curCommandPt = curCommand.GetPointer();
210 if ( std::strcmp( curCommand->GetDeviceType(), "STT_BIND" ) == 0 )
211 {
212 fps = ((igtl::StartBindMessage*)curCommandPt)->GetResolution();
213 }
214 else if ( std::strcmp( curCommand->GetDeviceType(), "STT_QTDATA" ) == 0 )
215 {
216 fps = ((igtl::StartQuaternionTrackingDataMessage*)curCommandPt)->GetResolution();
217 }
218 else if ( std::strcmp( curCommand->GetDeviceType(), "STT_TDATA" ) == 0 )
219 {
220 fps = ((igtl::StartTrackingDataMessage*)curCommandPt)->GetResolution();
221 }
222
223 this->StartStreamingOfSource(source, fps);
224 }
225 else if ( isSTPMsg )
226 {
227 this->StopStreamingOfSource(source);
228 }
229 else
230 {
231 //do nothing
232 }
233 }
234}
235
237{
238 return m_IsStreaming;
239}
240
242 unsigned int fps)
243{
244 if ( src == nullptr )
245 return;
246
247 //so far the provider allows the streaming of a single source only
248 //if the streaming thread is already running return a RTS message
249 if ( !m_IsStreaming )
250 {
251 //if it is a stream establish a connection between the provider and the
252 //source
253 this->ConnectTo(src);
254
255 // calculate the streaming time
256 this->m_StreamingTimeMutex.lock();
257 this->m_StreamingTime = 1.0 / (double) fps * 1000.0;
258 this->m_StreamingTimeMutex.unlock();
259
265 //this->m_ThreadId = m_MultiThreader->SpawnThread(this->TimerThread, this);
266
267 mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread(
268 this->m_StreamingCommand);
269
270 this->m_IsStreaming = true;
271 }
272 else
273 {
274 MITK_WARN("IGTLMessageProvider") << "This provider just supports the "
275 "streaming of one source.";
276 }
277}
278
280{
281 this->InvokeEvent(StreamingStartRequiredEvent());
282}
283
285{
286 this->InvokeEvent(StreamingStopRequiredEvent());
287}
288
290{
291 //this is something bad!!! The streaming thread has to be stopped before the
292 //source is disconnected otherwise it can cause a crash. This has to be added!!
293 this->DisconnectFrom(src);
294
295 mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread(
296 this->m_StopStreamingCommand);
297
298 //does this flag needs a mutex???
299 this->m_IsStreaming = false;
300}
301
303{
304 // \todo remove all inputs
305
306 mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread(
307 this->m_StopStreamingCommand);
308
309 //does this flag needs a mutex???
310 this->m_IsStreaming = false;
311}
312
313mitk::IGTLMessageSource::Pointer mitk::IGTLMessageProvider::GetFittingSource(const char* requestedType)
314{
315 //get the context
316 us::ModuleContext* context = us::GetModuleContext();
317 //define the interface name
318 std::string interface = mitk::IGTLMessageSource::US_INTERFACE_NAME;
319 //specify a filter that defines the requested type
320 std::string filter = "(" + mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE +
321 "=" + requestedType + ")";
322 //find the fitting service
323 std::vector<us::ServiceReferenceU> serviceReferences =
324 context->GetServiceReferences(interface, filter);
325
326 //check if a service reference was found. It is also possible that several
327 //services were found. This is not checked here, just the first one is taken.
328 if ( serviceReferences.size() )
329 {
330 mitk::IGTLMessageSource::Pointer curSource =
331 context->GetService<mitk::IGTLMessageSource>(serviceReferences.front());
332
333 if ( curSource.IsNotNull() )
334 return curSource;
335 }
336 //no service reference was found or found service reference has no valid source
337 return nullptr;
338}
339
340void mitk::IGTLMessageProvider::Send(mitk::IGTLMessage::Pointer msg)
341{
342 if (msg != nullptr)
343 {
344 MITK_INFO << "Sending OpenIGTLink Message: " << msg->ToString();
345 this->m_IGTLDevice->SendMessage(msg);
346 }
347}
348
349void
351{
352 for (DataObjectPointerArraySizeType i = 0;
353 i < UpstreamFilter->GetNumberOfOutputs(); i++)
354 {
355 this->SetInput(i, UpstreamFilter->GetOutput(i));
356 }
357}
358
359void
361{
362 if (UpstreamFilter == nullptr)
363 return;
364
365 for (DataObjectPointerArraySizeType i = 0; i < UpstreamFilter->GetNumberOfOutputs(); ++i)
366 {
367 auto input = UpstreamFilter->GetOutput(i);
368
369 if (input == nullptr)
370 continue;
371
372 auto nb = this->GetNumberOfIndexedInputs();
373
374 for (DataObjectPointerArraySizeType i = 0; i < nb; ++i)
375 {
376 if (this->GetInput(i) == input)
377 {
378 this->RemoveInput(i);
379 break;
380 }
381 }
382 }
383}
Connects a mitk::IGTLDevice to a MITK-OpenIGTLink-Message-Filter-Pipeline.
mitk::IGTLMessageSource::Pointer GetFittingSource(const char *requestedType)
Looks for microservices that provide messages with the requested type.
void StartStreamingOfSource(mitk::IGTLMessageSource *src, unsigned int fps)
Starts the streaming of the given message source with the given fps.
void CreateOutputs()
Create the necessary outputs for the m_IGTLDevice.
void OnIncomingCommand() override
This method is called when the IGTL device hold by this class receives a new command.
bool IsStreaming()
Returns the streaming state.
void StopStreamingOfSource(mitk::IGTLMessageSource *src)
Stops the streaming of the given message source.
void ConnectTo(mitk::IGTLMessageSource *UpstreamFilter)
Connects the input of this filter to the outputs of the given IGTLMessageSource.
void Send(mitk::IGTLMessage::Pointer msg)
sends the msg to the requesting client
void OnIncomingMessage() override
This method is called when the IGTL device hold by this class receives a new message.
void DisconnectFrom(mitk::IGTLMessageSource *UpstreamFilter)
Disconnects this filter from the outputs of the given IGTLMessageSource.
void OnLostConnection() override
This method is called when the IGTL device lost the connection to the other side.
void GenerateData() override
filter execute method
void StopStreamingOfAllSources()
Stops the streaming of all message source.
OpenIGTLink message source.
static const std::string US_INTERFACE_NAME
These Constants are used in conjunction with Microservices.
static const std::string US_PROPKEY_DEVICETYPE
IGTLMessage * GetOutput(void)
return the output (output with id 0) of the filter
A wrapper for the OpenIGTLink message type.
std::string RemoveRequestPrefixes(std::string requestType)
IGT Exceptions.
itkEventMacroDefinition(MessageSentEvent, itk::AnyEvent)