Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
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.