Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkIGTLMessageProvider.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
18 
19 #include "mitkIGTLDevice.h"
20 #include "mitkIGTLMessage.h"
21 #include "mitkIGTLMessageFactory.h"
22 
24 
25 //Microservices
26 #include "usServiceReference.h"
27 #include "usModuleContext.h"
28 #include "usServiceEvent.h"
29 #include "mitkServiceInterface.h"
30 #include "usGetModuleContext.h"
31 
32 //igt (remove this later)
33 #include "igtlBindMessage.h"
34 #include "igtlQuaternionTrackingDataMessage.h"
35 #include "igtlTrackingDataMessage.h"
36 
37 #ifndef WIN32
38 #include <unistd.h>
39 #endif
40 
43 {
44  this->SetName("IGTLMessageProvider");
45  //m_MultiThreader = itk::MultiThreader::New();
46  m_StreamingTimeMutex = itk::FastMutexLock::New();
47  //m_StopStreamingThreadMutex = itk::FastMutexLock::New();
48  //m_ThreadId = 0;
49  m_IsStreaming = false;
50 
51  // Create a command object. The function will be called later from the main thread
52  this->m_StopStreamingCommand = ProviderCommand::New();
53  m_StopStreamingCommand->SetCallbackFunction(this,
55 
56  this->m_StreamingCommand = ProviderCommand::New();
57  m_StreamingCommand->SetCallbackFunction(this,
59 }
60 
62 {
64  //this->m_StopStreamingThreadMutex->Lock();
65  //this->m_StopStreamingThread = true;
66  //this->m_StopStreamingThreadMutex->Unlock();
67  //if ( m_ThreadId >= 0)
68  //{
69  // this->m_MultiThreader->TerminateThread(m_ThreadId);
70  //}
71  this->InvokeEvent(StreamingStartRequiredEvent());
72 }
73 
75 {
76 
78 
79  if (this->GetInput() != nullptr)
80  {
81  igtl::MessageBase::Pointer curMessage = this->GetInput()->GetMessage();
82  if (dynamic_cast<igtl::TrackingDataMessage*>(curMessage.GetPointer()) != nullptr)
83  {
84  igtl::TrackingDataMessage* tdMsg =
85  (igtl::TrackingDataMessage*)(curMessage.GetPointer());
87  tdMsg->GetTrackingDataElement(0, trackingData);
88  float x_pos, y_pos, z_pos;
89  trackingData->GetPosition(&x_pos, &y_pos, &z_pos);
90  }
91  }
92 }
93 
95 {
96  if (this->m_IGTLDevice.IsNull())
97  return;
98 
99  for (unsigned int index = 0; index < this->GetNumberOfIndexedInputs(); index++)
100  {
101  const IGTLMessage* msg = this->GetInput(index);
102  if (msg == nullptr)
103  {
104  continue;
105  }
106 
107  if ( !msg->IsDataValid() )
108  {
109  continue;
110  }
111 
112  igtl::MessageBase::Pointer igtlMsg = msg->GetMessage();
113 
114  if ( igtlMsg.IsNotNull() )
115  {
116  //send the message
117  this->m_IGTLDevice->SendMessage(igtlMsg);
118  }
119  }
120 }
121 
123 {
124  //if outputs are set then delete them
125  if (this->GetNumberOfOutputs() > 0)
126  {
127  for (int numOP = this->GetNumberOfOutputs() - 1; numOP >= 0; numOP--)
128  this->RemoveOutput(numOP);
129  this->Modified();
130  }
131 
132  //fill the outputs if a valid OpenIGTLink device is set
133  if (m_IGTLDevice.IsNull())
134  return;
135 
136  this->SetNumberOfIndexedOutputs(1);
137  if (this->GetOutput(0) == NULL)
138  {
139  DataObjectPointer newOutput = this->MakeOutput(0);
140  this->SetNthOutput(0, newOutput);
141  this->Modified();
142  }
143 }
144 
145 //void mitk::IGTLMessageProvider::UpdateOutputInformation()
146 //{
147 // this->Modified(); // make sure that we need to be updated
148 // Superclass::UpdateOutputInformation();
149 //}
150 
151 
153 {
154 
155 }
156 
158 {
159  //in case the provider is streaming at the moment we have to stop it
160  if (m_IsStreaming)
161  {
162  MITK_DEBUG("IGTLMessageProvider") << "lost connection, stop streaming";
163  this->StopStreamingOfAllSources();
164  }
165 }
166 
167 std::string RemoveRequestPrefixes(std::string requestType)
168 {
169  return requestType.substr(4);
170 }
171 
173 {
174  //get the next command
175  igtl::MessageBase::Pointer curCommand = this->m_IGTLDevice->GetNextCommand();
176  //extract the type
177  const char * requestType = curCommand->GetDeviceType();
178  //check the type
179  std::string reqType(requestType);
180  bool isGetMsg = !reqType.find("GET_");
181  bool isSTTMsg = !reqType.find("STT_");
182  bool isSTPMsg = !reqType.find("STP_");
183  bool isRTSMsg = !reqType.find("RTS_");
184  //get the type from the request type (remove STT_, STP_, GET_, RTS_)
185  std::string type = RemoveRequestPrefixes(requestType);
186  //check all microservices if there is a fitting source for the requested type
187  mitk::IGTLMessageSource::Pointer source = this->GetFittingSource(type.c_str());
188  //if there is no fitting source return a RTS message, if there is a RTS
189  //type defined in the message factory send it
190  if ( source.IsNull() )
191  {
192  if ( !this->GetIGTLDevice()->SendRTSMessage(type.c_str()) )
193  {
194  //sending RTS message failed, probably because the type is not in the
195  //message factory
196  MITK_WARN("IGTLMessageProvider") << "Tried to send a RTS message but did "
197  "not succeed. Check if this type ( "
198  << type << " ) was added to the message "
199  "factory. ";
200  }
201  }
202  else
203  {
204  if ( isGetMsg ) //if it is a single value push it into sending queue
205  {
206  //first it is necessary to update the source. This needs additional time
207  //but is necessary. But are we really allowed to call this here? In which
208  //thread are we? Is the source thread safe?
209  source->Update();
210  mitk::IGTLMessage::Pointer sourceOutput = source->GetOutput();
211  if (sourceOutput.IsNotNull() && sourceOutput->IsDataValid())
212  {
213  igtl::MessageBase::Pointer sourceMsg = sourceOutput->GetMessage();
214  if ( source.IsNotNull() )
215  {
216  this->GetIGTLDevice()->SendMessage(sourceMsg);
217  }
218  }
219  }
220  else if ( isSTTMsg )
221  {
222  //read the requested frames per second
223  int fps = 10;
224 
225  //read the fps from the command
226  igtl::MessageBase* curCommandPt = curCommand.GetPointer();
227  if ( std::strcmp( curCommand->GetDeviceType(), "STT_BIND" ) == 0 )
228  {
229  fps = ((igtl::StartBindMessage*)curCommandPt)->GetResolution();
230  }
231  else if ( std::strcmp( curCommand->GetDeviceType(), "STT_QTDATA" ) == 0 )
232  {
233  fps = ((igtl::StartQuaternionTrackingDataMessage*)curCommandPt)->GetResolution();
234  }
235  else if ( std::strcmp( curCommand->GetDeviceType(), "STT_TDATA" ) == 0 )
236  {
237  fps = ((igtl::StartTrackingDataMessage*)curCommandPt)->GetResolution();
238  }
239 
240  this->StartStreamingOfSource(source, fps);
241  }
242  else if ( isSTPMsg )
243  {
244  this->StopStreamingOfSource(source);
245  }
246  else
247  {
248  //do nothing
249  }
250  }
251 }
252 
254 {
255  return m_IsStreaming;
256 }
257 
259  unsigned int fps)
260 {
261  if ( src == NULL )
262  return;
263 
264  //so far the provider allows the streaming of a single source only
265  //if the streaming thread is already running return a RTS message
266  if ( !m_IsStreaming )
267  {
268  //if it is a stream establish a connection between the provider and the
269  //source
270  this->ConnectTo(src);
271 
272  // calculate the streaming time
273  this->m_StreamingTimeMutex->Lock();
274  this->m_StreamingTime = 1.0 / (double) fps * 1000.0;
275  this->m_StreamingTimeMutex->Unlock();
276 
282  //this->m_ThreadId = m_MultiThreader->SpawnThread(this->TimerThread, this);
283 
285  this->m_StreamingCommand);
286 
287  this->m_IsStreaming = true;
288  }
289  else
290  {
291  MITK_WARN("IGTLMessageProvider") << "This provider just supports the "
292  "streaming of one source.";
293  }
294 }
295 
297 {
298  this->InvokeEvent(StreamingStartRequiredEvent());
299 }
300 
302 {
303  this->InvokeEvent(StreamingStopRequiredEvent());
304 }
305 
307 {
308  //this is something bad!!! The streaming thread has to be stopped before the
309  //source is disconnected otherwise it can cause a crash. This has to be added!!
310  this->DisconnectFrom(src);
311 
312  //this->m_StopStreamingThreadMutex->Lock();
313  //this->m_StopStreamingThread = true;
314  //this->m_StopStreamingThreadMutex->Unlock();
315 
317  this->m_StopStreamingCommand);
318 
319  //does this flag needs a mutex???
320  this->m_IsStreaming = false;
321 }
322 
324 {
325  // \todo remove all inputs
326 
328  this->m_StopStreamingCommand);
329 
330  //does this flag needs a mutex???
331  this->m_IsStreaming = false;
332 }
333 
335 {
336  //get the context
337  us::ModuleContext* context = us::GetModuleContext();
338  //define the interface name
339  std::string interface = mitk::IGTLMessageSource::US_INTERFACE_NAME;
340  //specify a filter that defines the requested type
341  std::string filter = "(" + mitk::IGTLMessageSource::US_PROPKEY_DEVICETYPE +
342  "=" + requestedType + ")";
343  //find the fitting service
344  std::vector<us::ServiceReferenceU> serviceReferences =
345  context->GetServiceReferences(interface, filter);
346 
347  //check if a service reference was found. It is also possible that several
348  //services were found. This is not checked here, just the first one is taken.
349  if ( serviceReferences.size() )
350  {
352  context->GetService<mitk::IGTLMessageSource>(serviceReferences.front());
353 
354  if ( curSource.IsNotNull() )
355  return curSource;
356  }
357  //no service reference was found or found service reference has no valid source
358  return NULL;
359 }
360 
362 {
363  if (msg != NULL)
364  this->m_IGTLDevice->SendMessage(msg);
365 }
366 
367 void
369 {
370  for (DataObjectPointerArraySizeType i = 0;
371  i < UpstreamFilter->GetNumberOfOutputs(); i++)
372  {
373  this->SetInput(i, UpstreamFilter->GetOutput(i));
374  }
375 }
376 
377 void
379 {
380  for (DataObjectPointerArraySizeType i = 0;
381  i < UpstreamFilter->GetNumberOfOutputs(); i++)
382  {
383  this->RemoveInput(UpstreamFilter->GetOutput(i));
384  }
385 }
386 
387 //ITK_THREAD_RETURN_TYPE mitk::IGTLMessageProvider::TimerThread(void* pInfoStruct)
388 //{
389 // // extract this pointer from thread info structure
390 // struct itk::MultiThreader::ThreadInfoStruct * pInfo =
391 // (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
392 // mitk::IGTLMessageProvider* thisObject =
393 // static_cast<mitk::IGTLMessageProvider*>(pInfo->UserData);
394 //
395 // itk::SimpleMutexLock mutex;
396 // mutex.Lock();
397 //
398 // thisObject->m_StopStreamingThreadMutex->Lock();
399 // thisObject->m_StopStreamingThread = false;
400 // thisObject->m_StopStreamingThreadMutex->Unlock();
401 //
402 // thisObject->m_StreamingTimeMutex->Lock();
403 // unsigned int waitingTime = thisObject->m_StreamingTime;
404 // thisObject->m_StreamingTimeMutex->Unlock();
405 //
406 // while (true)
407 // {
408 // thisObject->m_StopStreamingThreadMutex->Lock();
409 // bool stopThread = thisObject->m_StopStreamingThread;
410 // thisObject->m_StopStreamingThreadMutex->Unlock();
411 //
412 // if (stopThread)
413 // {
414 // break;
415 // }
416 //
417 // //wait for the time given
418 // //I know it is not the nicest solution but we just need an approximate time
419 // //sleeps for 20 ms
420 // #if defined (WIN32) || defined (_WIN32)
421 // Sleep(waitingTime);
422 // #else
423 // usleep(waitingTime * 1000);
424 // #endif
425 //
426 // // Ask to execute that command from the GUI thread
427 // mitk::CallbackFromGUIThread::GetInstance()->CallThisFromGUIThread(
428 // thisObject->m_StreamingCommand);
429 // }
430 //
431 // thisObject->m_ThreadId = 0;
432 //
433 // mutex.Unlock();
434 //
435 // return ITK_THREAD_RETURN_VALUE;
436 //}
virtual bool IsDataValid() const
returns true if the object contains valid data
virtual igtl::MessageBase::Pointer GetMessage() const
returns the OpenIGTLink message
itk::SmartPointer< Self > Pointer
virtual void OnLostConnection() override
This method is called when the IGTL device lost the connection to the other side. ...
virtual void Update() override
Connects a mitk::IGTLDevice to a MITK-OpenIGTLink-Message-Filter-Pipeline.
static void Update(vtkPolyData *)
Definition: mitkSurface.cpp:35
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
mitk::IGTLMessageSource::Pointer GetFittingSource(const char *requestedType)
Looks for microservices that provide messages with the requested type.
void StopStreamingOfSource(mitk::IGTLMessageSource *src)
Stops the streaming of the given message source.
void CreateOutputs()
Create the necessary outputs for the m_IGTLDevice.
bool IsStreaming()
Returns the streaming state.
void StopStreamingOfAllSources()
Stops the streaming of all message source.
void StartStreamingOfSource(mitk::IGTLMessageSource *src, unsigned int fps)
Starts the streaming of the given message source with the given fps.
IGTLMessage * GetOutput(void)
return the output (output with id 0) of the filter
#define MITK_WARN
Definition: mitkLogMacros.h:23
A wrapper for the OpenIGTLink message type.
void Send(const IGTLMessage *msg)
sends the msg to the requesting client
static const std::string US_PROPKEY_DEVICETYPE
void CallThisFromGUIThread(itk::Command *, itk::EventObject *e=nullptr)
Change the current application cursor.
void DisconnectFrom(mitk::IGTLMessageSource *UpstreamFilter)
Disconnects this filter from the outputs of the given IGTLMessageSource.
static CallbackFromGUIThread * GetInstance()
This class is a singleton.
OpenIGTLink message source.
virtual void OnIncomingCommand() override
This method is called when the IGTL device hold by this class receives a new command.
virtual void OnIncomingMessage() override
This method is called when the IGTL device hold by this class receives a new message.
virtual void SetName(std::string _arg)
Sets the human readable name of this source. There is also a default name, but you can use this metho...
virtual void GenerateData() override
filter execute method
static const std::string US_INTERFACE_NAME
These Constants are used in conjunction with Microservices.
void ConnectTo(mitk::IGTLMessageSource *UpstreamFilter)
Connects the input of this filter to the outputs of the given IGTLMessageSource.
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
std::string RemoveRequestPrefixes(std::string requestType)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.