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
mitkIGTLDevice.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 
17 #include "mitkIGTLDevice.h"
18 //#include "mitkIGTException.h"
19 //#include "mitkIGTTimeStamp.h"
20 #include <itkMutexLockHolder.h>
21 #include <itksys/SystemTools.hxx>
22 #include <cstring>
23 
24 #include <igtlTransformMessage.h>
25 #include <mitkIGTLMessageCommon.h>
26 
27 #include <igtl_status.h>
28 
29 //remove later
30 #include <igtlTrackingDataMessage.h>
31 
32 //TODO: Which timeout is acceptable and also needed to transmit image data? Is there a maximum data limit?
33 static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC = 100;
35 
37 // m_Data(mitk::DeviceDataUnspecified),
38 m_State(mitk::IGTLDevice::Setup),
39 m_Name("Unspecified Device"),
40 m_StopCommunication(false),
41 m_Hostname("127.0.0.1"),
42 m_PortNumber(-1),
43 m_MultiThreader(nullptr), m_SendThreadID(0), m_ReceiveThreadID(0), m_ConnectThreadID(0)
44 {
45  m_ReadFully = ReadFully;
48  // m_LatestMessageMutex = itk::FastMutexLock::New();
52  // execution rights are owned by the application thread at the beginning
53  m_SendingFinishedMutex->Lock();
56  m_MultiThreader = itk::MultiThreader::New();
57  // m_Data = mitk::DeviceDataUnspecified;
58  // m_LatestMessage = igtl::MessageBase::New();
59 
62 }
63 
65 {
66  /* stop communication and disconnect from igtl device */
67  if (GetState() == Running)
68  {
69  this->StopCommunication();
70  this->CloseConnection();
71  }
72  else if (GetState() == Ready)
73  {
74  this->CloseConnection();
75  }
76  /* cleanup tracking thread */
77  if (m_MultiThreader.IsNotNull())
78  {
79  if ((m_SendThreadID != 0))
80  {
81  m_MultiThreader->TerminateThread(m_SendThreadID);
82  }
83  if ((m_ReceiveThreadID != 0))
84  {
85  m_MultiThreader->TerminateThread(m_ReceiveThreadID);
86  }
87  if ((m_ConnectThreadID != 0))
88  {
89  m_MultiThreader->TerminateThread(m_ConnectThreadID);
90  }
91  }
92  m_MultiThreader = nullptr;
93 }
94 
96 {
97  MutexLockHolder lock(*m_StateMutex);
98  return m_State;
99 }
100 
102 {
103  itkDebugMacro("setting m_State to " << state);
104 
105  m_StateMutex->Lock();
106  // MutexLockHolder lock(*m_StateMutex); // lock and unlock the mutex
107 
108  if (m_State == state)
109  {
110  m_StateMutex->Unlock();
111  return;
112  }
113  m_State = state;
114  m_StateMutex->Unlock();
115  this->Modified();
116 }
117 
119 {
120  return true;
121 }
122 
123 unsigned int mitk::IGTLDevice::ReceivePrivate(igtl::Socket* socket)
124 {
125  // Create a message buffer to receive header
127  headerMsg = igtl::MessageHeader::New();
128 
129  // Initialize receive buffer
130  headerMsg->InitPack();
131 
132  // Receive generic header from the socket
133  int r =
134  socket->Receive(headerMsg->GetPackPointer(), headerMsg->GetPackSize(), 0);
135 
136  //MITK_INFO << "Server received r = " << r;
137 
138  MITK_INFO << "Received r = " << r;
139 
140  if (r == 0) //connection error
141  {
142  // an error was received, therefore the communication with this socket
143  // must be stoppedy
144  return IGTL_STATUS_NOT_PRESENT;
145  }
146  else if (r == -1) //timeout
147  {
148  // a timeout was received, this is no error state, thus, do nothing
149  return IGTL_STATUS_TIME_OUT;
150  }
151  else if (r == headerMsg->GetPackSize())
152  {
153  // Deserialize the header and check the CRC
154  // ERROR HERE: This probably means the header data is corrupted...
155  int crcCheck = headerMsg->Unpack(1);
156 
157  if (crcCheck & igtl::MessageHeader::UNPACK_HEADER)
158  {
159  // Allocate a time stamp
161  ts = igtl::TimeStamp::New();
162 
163  // Get time stamp
164  igtlUint32 sec;
165  igtlUint32 nanosec;
166 
167  headerMsg->GetTimeStamp(ts);
168  ts->GetTimeStamp(&sec, &nanosec);
169 
170  // std::cerr << "Time stamp: "
171  // << sec << "."
172  // << nanosec << std::endl;
173 
174  // std::cerr << "Dev type and name: " << headerMsg->GetDeviceType() << " "
175  // << headerMsg->GetDeviceName() << std::endl;
176 
177  // headerMsg->Print(std::cout);
178 
179  //check the type of the received message
180  //if it is a GET_, STP_ or RTS_ command push it into the command queue
181  //otherwise continue reading the whole message from the socket
182  const char* curDevType = headerMsg->GetDeviceType();
183  if (std::strstr(curDevType, "GET_") != nullptr ||
184  std::strstr(curDevType, "STP_") != nullptr ||
185  std::strstr(curDevType, "RTS_") != nullptr)
186  {
187  this->m_MessageQueue->PushCommandMessage(headerMsg);
188  this->InvokeEvent(CommandReceivedEvent());
189  return IGTL_STATUS_OK;
190  }
191 
192  //Create a message according to the header message
193  igtl::MessageBase::Pointer curMessage;
194  curMessage = m_MessageFactory->CreateInstance(headerMsg);
195 
196  //check if the curMessage is created properly, if not the message type is
197  //not supported and the message has to be skipped
198  if (curMessage.IsNull())
199  {
200  socket->Skip(headerMsg->GetBodySizeToRead(), 0);
201  // MITK_ERROR("IGTLDevice") << "The received type is not supported. Please "
202  // "add it to the message factory.";
203  return IGTL_STATUS_NOT_FOUND;
204  }
205 
206  //insert the header to the message and allocate the pack
207  curMessage->SetMessageHeader(headerMsg);
208  curMessage->AllocatePack();
209 
210  // Receive transform data from the socket
211  int receiveCheck = 0;
212  receiveCheck = socket->Receive(curMessage->GetPackBodyPointer(),
213  curMessage->GetPackBodySize(), m_ReadFully);
214 
215  if (receiveCheck > 0)
216  {
217  int c = curMessage->Unpack(1);
218  if (!(c & igtl::MessageHeader::UNPACK_BODY))
219  {
220  return IGTL_STATUS_CHECKSUM_ERROR;
221  }
222 
223  //check the type of the received message
224  //if it is a command push it into the command queue
225  //otherwise into the normal receive queue
226  //STP_ commands are handled here because they implemented additional
227  //member variables that are not stored in the header message
228  if (std::strstr(curDevType, "STT_") != nullptr)
229  {
230  this->m_MessageQueue->PushCommandMessage(curMessage);
231  this->InvokeEvent(CommandReceivedEvent());
232  }
233  else
234  {
235  this->m_MessageQueue->PushMessage(curMessage);
236  this->InvokeEvent(MessageReceivedEvent());
237  }
238  return IGTL_STATUS_OK;
239  }
240  else
241  {
242  MITK_ERROR("IGTLDevice") << "Received a valid header but could not "
243  << "read the whole message.";
244  return IGTL_STATUS_UNKNOWN_ERROR;
245  }
246  }
247  else
248  {
249  //CRC check failed
250  MITK_ERROR << "CRC Check failed";
251  return IGTL_STATUS_CHECKSUM_ERROR;
252  }
253  }
254  else
255  {
256  //Message size information and actual data size don't match.
257  //this state is not suppossed to be reached, return unknown error
258  MITK_ERROR << "IGTL status unknown";
259  return IGTL_STATUS_UNKNOWN_ERROR;
260  }
261 }
262 
264 {
265  this->SendMessage(msg->GetMessage());
266 }
267 
269 {
270  //add the message to the queue
271  m_MessageQueue->PushSendMessage(msg);
272 }
273 
275  igtl::Socket::Pointer socket)
276 {
277  //check the input message
278  if (msg.IsNull())
279  {
280  MITK_ERROR("IGTLDevice") << "Could not send message because message is not "
281  "valid. Please check.";
282  return false;
283  }
284 
285  // add the name of this device to the message
286  msg->SetDeviceName(this->GetName().c_str());
287 
288  // Pack (serialize) and send
289  msg->Pack();
290 
291  int sendSuccess = socket->Send(msg->GetPackPointer(), msg->GetPackSize());
292 
293  if (sendSuccess)
294  {
295  this->InvokeEvent(MessageSentEvent());
296  return IGTL_STATUS_OK;
297  }
298  else
299  {
300  return IGTL_STATUS_UNKNOWN_ERROR;
301  }
302 }
303 
304 void mitk::IGTLDevice::RunCommunication(void (IGTLDevice::*ComFunction)(void), itk::FastMutexLock* mutex)
305 {
306  if (this->GetState() != Running)
307  return;
308 
309  try
310  {
311  // keep lock until end of scope
312  MutexLockHolder communicationFinishedLockHolder(*mutex);
313 
314  // Because m_StopCommunication is used by two threads, access has to be guarded
315  // by a mutex. To minimize thread locking, a local copy is used here
316  bool localStopCommunication;
317 
318  // update the local copy of m_StopCommunication
319  this->m_StopCommunicationMutex->Lock();
320  localStopCommunication = this->m_StopCommunication;
321  this->m_StopCommunicationMutex->Unlock();
322  while ((this->GetState() == Running) && (localStopCommunication == false))
323  {
324  (this->*ComFunction)();
325 
326  /* Update the local copy of m_StopCommunication */
327  this->m_StopCommunicationMutex->Lock();
328  localStopCommunication = m_StopCommunication;
329  this->m_StopCommunicationMutex->Unlock();
330 
331  // time to relax, this sets the maximum ever possible framerate to 1000 Hz
332  itksys::SystemTools::Delay(1);
333  }
334  }
335  catch (...)
336  {
337  mutex->Unlock();
338  this->StopCommunication();
339  MITK_ERROR("IGTLDevice::RunCommunication") << "Error while communicating. Thread stopped.";
340  //mitkThrowException(mitk::IGTException) << "Error while communicating. Thread stopped.";
341  }
342  // StopCommunication was called, thus the mode should be changed back to Ready now
343  // that the tracking loop has ended.
344  //this->SetState(Ready); //this is done elsewhere
345  MITK_DEBUG("IGTLDevice::RunCommunication") << "Reached end of communication.";
346  // returning from this function (and ThreadStartCommunication())
347  // this will end the thread
348  return;
349 }
350 
352 {
353  if (this->GetState() != Ready)
354  return false;
355 
356  // go to mode Running
357  this->SetState(Running);
358 
359  // set a timeout for the sending and receiving
360  this->m_Socket->SetTimeout(SOCKET_SEND_RECEIVE_TIMEOUT_MSEC);
361 
362  // update the local copy of m_StopCommunication
363  this->m_StopCommunicationMutex->Lock();
364  this->m_StopCommunication = false;
365  this->m_StopCommunicationMutex->Unlock();
366 
367  // transfer the execution rights to tracking thread
368  m_SendingFinishedMutex->Unlock();
369  m_ReceivingFinishedMutex->Unlock();
370  m_ConnectingFinishedMutex->Unlock();
371 
372  // start new threads that execute the communication
373  m_SendThreadID =
374  m_MultiThreader->SpawnThread(this->ThreadStartSending, this);
375  m_ReceiveThreadID =
376  m_MultiThreader->SpawnThread(this->ThreadStartReceiving, this);
377  m_ConnectThreadID =
378  m_MultiThreader->SpawnThread(this->ThreadStartConnecting, this);
379  // mitk::IGTTimeStamp::GetInstance()->Start(this);
380  return true;
381 }
382 
384 {
385  if (this->GetState() == Running) // Only if the object is in the correct state
386  {
387  // m_StopCommunication is used by two threads, so we have to ensure correct
388  // thread handling
389  m_StopCommunicationMutex->Lock();
390  m_StopCommunication = true;
391  m_StopCommunicationMutex->Unlock();
392  // we have to wait here that the other thread recognizes the STOP-command
393  // and executes it
394  m_SendingFinishedMutex->Lock();
395  m_ReceivingFinishedMutex->Lock();
396  m_ConnectingFinishedMutex->Lock();
397  // mitk::IGTTimeStamp::GetInstance()->Stop(this); // notify realtime clock
398  // StopCommunication was called, thus the mode should be changed back
399  // to Ready now that the tracking loop has ended.
400  this->SetState(Ready);
401  }
402  return true;
403 }
404 
406 {
407  if (this->GetState() == Setup)
408  {
409  return true;
410  }
411  else if (this->GetState() == Running)
412  {
413  this->StopCommunication();
414  }
415 
416  m_Socket->CloseSocket();
417 
418  /* return to setup mode */
419  this->SetState(Setup);
420 
421  // this->InvokeEvent(mitk::LostConnectionEvent());
422 
423  return true;
424 }
425 
426 bool mitk::IGTLDevice::SendRTSMessage(const char* type)
427 {
428  //construct the device type for the return message, it starts with RTS_ and
429  //continues with the requested type
430  std::string returnType("RTS_");
431  returnType.append(type);
432  //create a return message
434  this->m_MessageFactory->CreateInstance(returnType);
435  //if retMsg is NULL there is no return message defined and thus it is not
436  //necessary to send one back
437  if (rtsMsg.IsNotNull())
438  {
439  this->SendMessage(rtsMsg);
440  return true;
441  }
442  else
443  {
444  return false;
445  }
446 }
447 
449 {
450  MITK_DEBUG << "mitk::IGTLDevice::Connect();";
451 }
452 
454 {
455  return this->m_MessageQueue->PullImage2dMessage();
456 }
457 
459 {
460  return this->m_MessageQueue->PullImage3dMessage();
461 }
462 
464 {
465  return this->m_MessageQueue->PullTransformMessage();
466 }
467 
469 {
470  igtl::TrackingDataMessage::Pointer msg = this->m_MessageQueue->PullTrackingMessage();
471  return msg;
472 }
473 
475 {
476  return this->m_MessageQueue->PullStringMessage();
477 }
478 
480 {
481  return this->m_MessageQueue->PullMiscMessage();
482 }
483 
485 {
486  return m_MessageQueue->PullCommandMessage();
487 }
488 
491  bool enable)
492 {
493  queue->EnableInfiniteBuffering(enable);
494 }
495 
496 ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartSending(void* pInfoStruct)
497 {
498  /* extract this pointer from Thread Info structure */
499  struct itk::MultiThreader::ThreadInfoStruct * pInfo =
500  (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
501  if (pInfo == nullptr)
502  {
503  return ITK_THREAD_RETURN_VALUE;
504  }
505  if (pInfo->UserData == nullptr)
506  {
507  return ITK_THREAD_RETURN_VALUE;
508  }
509  IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData;
510  if (igtlDevice != nullptr)
511  {
513  }
514  igtlDevice->m_SendThreadID = 0; // erase thread id because thread will end.
515  return ITK_THREAD_RETURN_VALUE;
516 }
517 
518 ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartReceiving(void* pInfoStruct)
519 {
520  /* extract this pointer from Thread Info structure */
521  struct itk::MultiThreader::ThreadInfoStruct * pInfo =
522  (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
523  if (pInfo == nullptr)
524  {
525  return ITK_THREAD_RETURN_VALUE;
526  }
527  if (pInfo->UserData == nullptr)
528  {
529  return ITK_THREAD_RETURN_VALUE;
530  }
531  IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData;
532  if (igtlDevice != nullptr)
533  {
535  igtlDevice->m_ReceivingFinishedMutex);
536  }
537  igtlDevice->m_ReceiveThreadID = 0; // erase thread id because thread will end.
538  return ITK_THREAD_RETURN_VALUE;
539 }
540 
541 ITK_THREAD_RETURN_TYPE mitk::IGTLDevice::ThreadStartConnecting(void* pInfoStruct)
542 {
543  /* extract this pointer from Thread Info structure */
544  struct itk::MultiThreader::ThreadInfoStruct * pInfo =
545  (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
546  if (pInfo == nullptr)
547  {
548  return ITK_THREAD_RETURN_VALUE;
549  }
550  if (pInfo->UserData == nullptr)
551  {
552  return ITK_THREAD_RETURN_VALUE;
553  }
554  IGTLDevice *igtlDevice = (IGTLDevice*)pInfo->UserData;
555  if (igtlDevice != nullptr)
556  {
558  igtlDevice->m_ConnectingFinishedMutex);
559  }
560  igtlDevice->m_ConnectThreadID = 0; // erase thread id because thread will end.
561  return ITK_THREAD_RETURN_VALUE;
562 }
itk::FastMutexLock::Pointer m_ReceivingFinishedMutex
itk::FastMutexLock::Pointer m_StopCommunicationMutex
virtual igtl::MessageBase::Pointer GetMessage() const
returns the OpenIGTLink message
mitk::IGTLMessageFactory::Pointer m_MessageFactory
itk::SmartPointer< Self > Pointer
void SetState(IGTLDeviceState state)
change object state
static ITK_THREAD_RETURN_TYPE ThreadStartConnecting(void *data)
static start method for the connection thread.
bool StartCommunication()
Starts the communication between the two devices.
IGTLDeviceState GetState() const
Returns current object state (Setup, Ready or Running)
igtl::MessageBase::Pointer GetNextMiscMessage()
#define MITK_INFO
Definition: mitkLogMacros.h:22
itk::FastMutexLock::Pointer m_StateMutex
#define MITK_ERROR
Definition: mitkLogMacros.h:24
unsigned int SendMessagePrivate(igtl::MessageBase::Pointer msg, igtl::Socket::Pointer socket)
Sends a message.
static const int SOCKET_SEND_RECEIVE_TIMEOUT_MSEC
itk::FastMutexLock::Pointer m_ConnectingFinishedMutex
void EnableInfiniteBufferingMode(mitk::IGTLMessageQueue::Pointer queue, bool enable=true)
Sets the buffering mode of the given queue.
#define MITK_DEBUG
Definition: mitkLogMacros.h:26
DataCollection - Class to facilitate loading/accessing structured data.
igtl::MessageBase::Pointer GetNextCommand()
Returns the oldest message in the command queue.
igtl::ImageMessage::Pointer GetNextImage2dMessage()
Returns the oldest message in the receive queue.
igtl::TransformMessage::Pointer GetNextTransformMessage()
igtl::ImageMessage::Pointer GetNextImage3dMessage()
virtual void Connect()
Call this method to check for other devices that want to connect to this one.
virtual void Send()=0
Call this method to send a message. The message will be read from the queue.
bool SendRTSMessage(const char *type)
Send RTS message of given type.
unsigned int ReceivePrivate(igtl::Socket *device)
Call this method to receive a message from the given device.
A wrapper for the OpenIGTLink message type.
virtual bool TestConnection()
TestConnection() tries to connect to a IGTL device on the current ip and port.
virtual void Receive()=0
Call this method to receive a message.
virtual bool CloseConnection()
Closes the connection to the device.
itk::MutexLockHolder< itk::FastMutexLock > MutexLockHolder
IGTLDeviceState
Type for state variable. The IGTLDevice is always in one of these states.
mitk::IGTLMessageQueue::Pointer m_MessageQueue
itk::FastMutexLock::Pointer m_SendingFinishedMutex
Interface for all OpenIGTLink Devices.
igtl::TrackingDataMessage::Pointer GetNextTrackingDataMessage()
virtual bool StopCommunication()
Stops the communication between the two devices.
static ITK_THREAD_RETURN_TYPE ThreadStartReceiving(void *data)
static start method for the receiving thread.
static ITK_THREAD_RETURN_TYPE ThreadStartSending(void *data)
static start method for the sending thread.
void SendMessage(igtl::MessageBase::Pointer msg)
Adds the given message to the sending queue.
static std::string GetName(std::string fileName, std::string suffix)
igtl::StringMessage::Pointer GetNextStringMessage()
static void Setup()
void RunCommunication(void(IGTLDevice::*ComFunction)(void), itk::FastMutexLock *mutex)
Continuously calls the given function.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.