Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.