PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusOpenIGTLinkServer.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "PlusConfigure.h"
9 #include "PlusCommon.h"
10 #include "igsioTrackedFrame.h"
11 #include "vtkPlusChannel.h"
12 #include "vtkPlusCommand.h"
14 #include "vtkPlusDataCollector.h"
18 #include "vtkIGSIORecursiveCriticalSection.h"
19 #include "vtkIGSIOTrackedFrameList.h"
20 #include "vtkIGSIOTransformRepository.h"
21 
22 // VTK includes
23 #include <vtkImageData.h>
24 #include <vtkObjectFactory.h>
25 #include <vtkPoints.h>
26 #include <vtkPolyData.h>
27 #include <vtkPolyDataReader.h>
28 
29 // OpenIGTLink includes
30 #include <igtlCommandMessage.h>
31 #include <igtlImageMessage.h>
32 #include <igtlImageMetaMessage.h>
33 #include <igtlMessageHeader.h>
35 #include <igtlPointMessage.h>
36 #include <igtlPolyDataMessage.h>
37 #include <igtlStatusMessage.h>
38 #include <igtlStringMessage.h>
39 #include <igtlTrackingDataMessage.h>
40 
41 // OpenIGTLinkIO includes
42 #include <igtlioPolyDataConverter.h>
43 
44 #if defined(WIN32)
46 #elif defined(__APPLE__)
48 #elif defined(__linux__)
50 #endif
51 
52 // STL includes
53 #include <fstream>
54 #include <streambuf>
55 
56 namespace
57 {
58  const double DELAY_ON_SENDING_ERROR_SEC = 0.02;
59  const double DELAY_ON_NO_NEW_FRAMES_SEC = 0.005;
60  const int NUMBER_OF_RECENT_COMMAND_IDS_STORED = 10;
61  const int IGTL_EMPTY_DATA_SIZE = -1;
62  const double SERVER_START_CHECK_DELAY_SEC = 2.0;
63  const double SERVER_START_CHECK_DELAY_INTERVAL_SEC = 0.05;
64 
65  //----------------------------------------------------------------------------
66  // If a frame cannot be retrieved from the device buffers (because it was overwritten by new frames)
67  // then we skip a SAMPLING_SKIPPING_MARGIN_SEC long period to allow the application to catch up.
68  // This time should be long enough to comfortably retrieve a frame from the buffer.
69  const double SAMPLING_SKIPPING_MARGIN_SEC = 0.1;
70 }
71 
72 //----------------------------------------------------------------------------
73 
75 int vtkPlusOpenIGTLinkServer::ClientIdCounter = 1;
76 const float vtkPlusOpenIGTLinkServer::CLIENT_SOCKET_TIMEOUT_SEC = 0.5f;
77 
78 //----------------------------------------------------------------------------
80  : ServerSocket(igtl::ServerSocket::New())
81  , TransformRepository(NULL)
82  , DataCollector(NULL)
83  , Threader(vtkSmartPointer<vtkMultiThreader>::New())
84  , IGTLProtocolVersion(OpenIGTLink_PROTOCOL_VERSION)
85  , IGTLHeaderVersion(IGTL_HEADER_VERSION_2)
86  , ListeningPort(-1)
87  , NumberOfRetryAttempts(10)
88  , DelayBetweenRetryAttemptsSec(0.05)
89  , MaxNumberOfIgtlMessagesToSend(100)
90  , ConnectionReceiverThreadId(-1)
91  , DataSenderThreadId(-1)
92  , IgtlMessageFactory(vtkSmartPointer<vtkPlusIgtlMessageFactory>::New())
93  , IgtlClientsMutex(vtkSmartPointer<vtkIGSIORecursiveCriticalSection>::New())
94  , LastSentTrackedFrameTimestamp(0)
95  , MaxTimeSpentWithProcessingMs(50)
96  , LastProcessingTimePerFrameMs(-1)
97  , SendValidTransformsOnly(true)
98  , DefaultClientSendTimeoutSec(CLIENT_SOCKET_TIMEOUT_SEC)
99  , DefaultClientReceiveTimeoutSec(CLIENT_SOCKET_TIMEOUT_SEC)
100  , IgtlMessageCrcCheckEnabled(0)
101  , PlusCommandProcessor(vtkSmartPointer<vtkPlusCommandProcessor>::New())
102  , MessageResponseQueueMutex(vtkSmartPointer<vtkIGSIORecursiveCriticalSection>::New())
103  , BroadcastChannel(NULL)
104  , LogWarningOnNoDataAvailable(true)
105  , KeepAliveIntervalSec(CLIENT_SOCKET_TIMEOUT_SEC / 2.0)
106  , GracePeriodLogLevel(vtkPlusLogger::LOG_LEVEL_DEBUG)
107  , MissingInputGracePeriodSec(0.0)
108  , BroadcastStartTime(0.0)
109  , NewClientConnected(false)
110 {
111 
112 }
113 
114 //----------------------------------------------------------------------------
116 {
117  this->Stop();
118  this->SetTransformRepository(NULL);
119  this->SetDataCollector(NULL);
120  this->SetConfigFilename(NULL);
121 }
122 
123 //----------------------------------------------------------------------------
125 {
126  bool found(false);
127  {
128  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
129  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
130  {
131  if (clientIterator->ClientId == clientId)
132  {
133  found = true;
134  break;
135  }
136  }
137  }
138 
139  if (!found)
140  {
141  LOG_ERROR("Requested clientId " << clientId << " not found in list.");
142  return PLUS_FAIL;
143  }
144 
145  igsioLockGuard<vtkIGSIORecursiveCriticalSection> mutexGuardedLock(this->MessageResponseQueueMutex);
146  this->MessageResponseQueue[clientId].push_back(message);
147 
148  return PLUS_SUCCESS;
149 }
150 
151 //----------------------------------------------------------------------------
152 void vtkPlusOpenIGTLinkServer::PrintSelf(ostream& os, vtkIndent indent)
153 {
154  this->Superclass::PrintSelf(os, indent);
155 }
156 
157 //----------------------------------------------------------------------------
159 {
160  if (this->DataCollector == NULL)
161  {
162  LOG_WARNING("Tried to start OpenIGTLink server without a vtkPlusDataCollector");
163  return PLUS_FAIL;
164  }
165 
166  if (this->ConnectionReceiverThreadId < 0)
167  {
168  this->ConnectionActive.Request = true;
169  this->ConnectionReceiverThreadId = this->Threader->SpawnThread((vtkThreadFunctionType)&ConnectionReceiverThread, this);
170  }
171 
172  if (this->DataSenderThreadId < 0)
173  {
174  this->DataSenderActive.Request = true;
175  this->DataSenderThreadId = this->Threader->SpawnThread((vtkThreadFunctionType)&DataSenderThread, this);
176  }
177 
178  // Wait a short duration to see if both threads initialized properly, check at 50ms interval
179  RETRY_UNTIL_TRUE(this->ConnectionActive.Respond,
180  vtkMath::Round(SERVER_START_CHECK_DELAY_SEC / SERVER_START_CHECK_DELAY_INTERVAL_SEC),
181  SERVER_START_CHECK_DELAY_INTERVAL_SEC);
182  if (!this->ConnectionActive.Respond)
183  {
184  LOG_ERROR("Unable to initialize receiver and sender processes.");
185  return PLUS_FAIL;
186  }
187 
188  std::ostringstream ss;
189  ss << "Data sent by default: ";
190  this->DefaultClientInfo.PrintSelf(ss, vtkIndent(0));
191  LOG_DEBUG(ss.str());
192 
193  this->PlusCommandProcessor->SetPlusServer(this);
194 
195  this->BroadcastStartTime = vtkIGSIOAccurateTimer::GetSystemTime();
196 
197  return PLUS_SUCCESS;
198 }
199 
200 //----------------------------------------------------------------------------
202 {
203  // Stop connection receiver thread
204  if (this->ConnectionReceiverThreadId >= 0)
205  {
206  this->ConnectionActive.Request = false;
207  while (this->ConnectionActive.Respond)
208  {
209  // Wait until the thread stops
210  vtkIGSIOAccurateTimer::DelayWithEventProcessing(0.2);
211  }
212  this->ConnectionReceiverThreadId = -1;
213  LOG_DEBUG("ConnectionReceiverThread stopped");
214  }
215 
216  // Disconnect clients (stop receiving thread, close socket)
217  std::vector< int > clientIds;
218  {
219  // Get all the client ids and release the lock
220  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
221  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
222  {
223  clientIds.push_back(clientIterator->ClientId);
224  }
225  }
226  for (std::vector< int >::iterator it = clientIds.begin(); it != clientIds.end(); ++it)
227  {
228  DisconnectClient(*it);
229  }
230 
231  LOG_INFO("Plus OpenIGTLink server stopped.");
232 
233  return PLUS_SUCCESS;
234 }
235 
236 //----------------------------------------------------------------------------
237 void* vtkPlusOpenIGTLinkServer::ConnectionReceiverThread(vtkMultiThreader::ThreadInfo* data)
238 {
240 
241  int r = self->ServerSocket->CreateServer(self->ListeningPort);
242  if (r < 0)
243  {
244  LOG_ERROR("Cannot create a server socket.");
245  return NULL;
246  }
247 
248  PrintServerInfo(self);
249 
250  self->ConnectionActive.Respond = true;
251 
252  // Wait for connections until we want to stop the thread
253  while (self->ConnectionActive.Request)
254  {
255  igtl::ClientSocket::Pointer newClientSocket = self->ServerSocket->WaitForConnection(CLIENT_SOCKET_TIMEOUT_SEC * 1000);
256  if (newClientSocket.IsNotNull())
257  {
258  // Lock before we change the clients list
259  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self->IgtlClientsMutex);
260  ClientData newClient;
261  self->IgtlClients.push_back(newClient);
262  self->NewClientConnected = true;
263 
264  ClientData* client = &(self->IgtlClients.back()); // get a reference to the client data that is stored in the list
265  client->ClientId = self->ClientIdCounter;
266  self->ClientIdCounter++;
267  client->ClientSocket = newClientSocket;
268  client->ClientSocket->SetReceiveTimeout(self->DefaultClientReceiveTimeoutSec * 1000);
269  client->ClientSocket->SetSendTimeout(self->DefaultClientSendTimeoutSec * 1000);
270  client->ClientInfo = self->DefaultClientInfo;
271  client->Server = self;
272 
273  // Setup vtkIGSIOFrameConverters for each stream
274  for (std::vector<PlusIgtlClientInfo::ImageStream>::iterator imageStreamIterator = client->ClientInfo.ImageStreams.begin();
275  imageStreamIterator != client->ClientInfo.ImageStreams.end(); ++imageStreamIterator)
276  {
277  PlusIgtlClientInfo::ImageStream* imageStream = &(*imageStreamIterator);
278  if (!imageStream->FrameConverter)
279  {
280  imageStream->FrameConverter = vtkSmartPointer<vtkIGSIOFrameConverter>::New();
281  }
282  }
283  for (std::vector<PlusIgtlClientInfo::VideoStream>::iterator videoStreamIterator = client->ClientInfo.VideoStreams.begin();
284  videoStreamIterator != client->ClientInfo.VideoStreams.end(); ++videoStreamIterator)
285  {
286  PlusIgtlClientInfo::VideoStream* videoStream = &(*videoStreamIterator);
287  if (!videoStream->FrameConverter)
288  {
289  videoStream->FrameConverter = vtkSmartPointer<vtkIGSIOFrameConverter>::New();
290  }
291  }
292 
293  int port = 0;
294  std::string address = "unknown";
295 #if (OPENIGTLINK_VERSION_MAJOR > 1) || ( OPENIGTLINK_VERSION_MAJOR == 1 && OPENIGTLINK_VERSION_MINOR > 9 ) || ( OPENIGTLINK_VERSION_MAJOR == 1 && OPENIGTLINK_VERSION_MINOR == 9 && OPENIGTLINK_VERSION_PATCH > 4 )
296  newClientSocket->GetSocketAddressAndPort(address, port);
297 #endif
298  LOG_INFO("Received new client connection (client " << client->ClientId << " at " << address << ":" << port << "). Number of connected clients: " << self->GetNumberOfConnectedClients());
299 
300  client->DataReceiverActive.first = true;
301  client->DataReceiverThreadId = self->Threader->SpawnThread((vtkThreadFunctionType)&DataReceiverThread, client);
302  }
303  }
304 
305  // Close server socket
306  if (self->ServerSocket.IsNotNull())
307  {
308  self->ServerSocket->CloseSocket();
309  }
310 
311  // Close thread
312  self->ConnectionReceiverThreadId = -1;
313  self->ConnectionActive.Respond = false;
314  return NULL;
315 }
316 
317 //----------------------------------------------------------------------------
318 void* vtkPlusOpenIGTLinkServer::DataSenderThread(vtkMultiThreader::ThreadInfo* data)
319 {
321  self->DataSenderActive.Respond = true;
322 
323  vtkPlusDevice* aDevice(NULL);
324  vtkPlusChannel* aChannel(NULL);
325 
326  DeviceCollection aCollection;
327  if (self->DataCollector->GetDevices(aCollection) != PLUS_SUCCESS || aCollection.size() == 0)
328  {
329  LOG_ERROR("Unable to retrieve devices. Check configuration and connection.");
330  return NULL;
331  }
332 
333  // Find the requested channel ID in all the devices
334  for (DeviceCollectionIterator it = aCollection.begin(); it != aCollection.end(); ++it)
335  {
336  aDevice = *it;
337  if (aDevice->GetOutputChannelByName(aChannel, self->GetOutputChannelId()) == PLUS_SUCCESS)
338  {
339  break;
340  }
341  }
342 
343  if (aChannel == NULL)
344  {
345  // The requested channel ID is not found
346  if (!self->GetOutputChannelId().empty())
347  {
348  // the user explicitly requested a specific channel, but none was found by that name
349  // this is an error
350  LOG_ERROR("Unable to start data sending. OutputChannelId not found: " << self->GetOutputChannelId());
351  return NULL;
352  }
353  // the user did not specify any channel, so just use the first channel that can be found in any device
354  for (DeviceCollectionIterator it = aCollection.begin(); it != aCollection.end(); ++it)
355  {
356  aDevice = *it;
357  if (aDevice->OutputChannelCount() > 0)
358  {
359  aChannel = *(aDevice->GetOutputChannelsStart());
360  break;
361  }
362  }
363  }
364 
365  // If we didn't find any channel then return
366  if (aChannel == NULL)
367  {
368  LOG_WARNING("There are no channels to broadcast. Only command processing is available.");
369  }
370 
371  self->BroadcastChannel = aChannel;
372  if (self->BroadcastChannel)
373  {
374  self->BroadcastChannel->GetMostRecentTimestamp(self->LastSentTrackedFrameTimestamp);
375  }
376 
377  double elapsedTimeSinceLastPacketSentSec = 0;
378  while (self->ConnectionActive.Request && self->DataSenderActive.Request)
379  {
380  bool clientsConnected = false;
381  {
382  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self->IgtlClientsMutex);
383  if (!self->IgtlClients.empty())
384  {
385  clientsConnected = true;
386  }
387  }
388  if (!clientsConnected)
389  {
390  // No client connected, wait for a while
391  vtkIGSIOAccurateTimer::Delay(0.2);
392  self->LastSentTrackedFrameTimestamp = 0; // next time start sending from the most recent timestamp
393  continue;
394  }
395 
396  if (self->HasGracePeriodExpired())
397  {
398  self->GracePeriodLogLevel = vtkPlusLogger::LOG_LEVEL_WARNING;
399  }
400 
401  SendMessageResponses(*self);
402 
403  // Send remote command execution replies to clients before sending any images/transforms/etc...
404  SendCommandResponses(*self);
405 
406  // Send image/tracking/string data
407  SendLatestFramesToClients(*self, elapsedTimeSinceLastPacketSentSec);
408  }
409  // Close thread
410  self->DataSenderThreadId = -1;
411  self->DataSenderActive.Respond = false;
412  return NULL;
413 }
414 
415 //----------------------------------------------------------------------------
417 {
418  vtkSmartPointer<vtkIGSIOTrackedFrameList> trackedFrameList = vtkSmartPointer<vtkIGSIOTrackedFrameList>::New();
419  double startTimeSec = vtkIGSIOAccurateTimer::GetSystemTime();
420 
421  // Acquire tracked frames since last acquisition (minimum 1 frame)
422  if (self.LastProcessingTimePerFrameMs < 1)
423  {
424  // if processing was less than 1ms/frame then assume it was 1ms (1000FPS processing speed) to avoid division by zero
425  self.LastProcessingTimePerFrameMs = 1;
426  }
427  int numberOfFramesToGet = std::max(self.MaxTimeSpentWithProcessingMs / self.LastProcessingTimePerFrameMs, 1);
428  // Maximize the number of frames to send
429  numberOfFramesToGet = std::min(numberOfFramesToGet, self.MaxNumberOfIgtlMessagesToSend);
430 
431  if (self.BroadcastChannel != NULL)
432  {
433  if ((self.BroadcastChannel->HasVideoSource() && !self.BroadcastChannel->GetVideoDataAvailable())
434  || (self.BroadcastChannel->ToolCount() > 0 && !self.BroadcastChannel->GetTrackingDataAvailable())
435  || (self.BroadcastChannel->FieldCount() > 0 && !self.BroadcastChannel->GetFieldDataAvailable()))
436  {
437  if (self.LogWarningOnNoDataAvailable)
438  {
439  LOG_DYNAMIC("No data is broadcasted, as no data is available yet.", self.GracePeriodLogLevel);
440  }
441  }
442  else
443  {
444  double oldestDataTimestamp = 0;
445  if (self.BroadcastChannel->GetOldestTimestamp(oldestDataTimestamp) == PLUS_SUCCESS)
446  {
447  if (self.LastSentTrackedFrameTimestamp < oldestDataTimestamp)
448  {
449  LOG_INFO("OpenIGTLink broadcasting started. No data was available between " << self.LastSentTrackedFrameTimestamp << "-" << oldestDataTimestamp << "sec, therefore no data were broadcasted during this time period.");
450  self.LastSentTrackedFrameTimestamp = oldestDataTimestamp + SAMPLING_SKIPPING_MARGIN_SEC;
451  }
452  static vtkIGSIOLogHelper logHelper(60.0, 500000);
453  CUSTOM_RETURN_WITH_FAIL_IF(self.BroadcastChannel->GetTrackedFrameList(self.LastSentTrackedFrameTimestamp, trackedFrameList, numberOfFramesToGet) != PLUS_SUCCESS,
454  "Failed to get tracked frame list from data collector (last recorded timestamp: " << std::fixed << self.LastSentTrackedFrameTimestamp);
455  }
456  }
457  }
458 
459  // There is no new frame in the buffer
460  if (trackedFrameList->GetNumberOfTrackedFrames() == 0)
461  {
462  vtkIGSIOAccurateTimer::Delay(DELAY_ON_NO_NEW_FRAMES_SEC);
463  elapsedTimeSinceLastPacketSentSec += vtkIGSIOAccurateTimer::GetSystemTime() - startTimeSec;
464 
465  // Send keep alive packet to clients
466  if (elapsedTimeSinceLastPacketSentSec > self.KeepAliveIntervalSec)
467  {
468  self.KeepAlive();
469  elapsedTimeSinceLastPacketSentSec = 0;
470  return PLUS_SUCCESS;
471  }
472 
473  return PLUS_FAIL;
474  }
475 
476  for (unsigned int i = 0; i < trackedFrameList->GetNumberOfTrackedFrames(); ++i)
477  {
478  // Send tracked frame
479  self.SendTrackedFrame(*trackedFrameList->GetTrackedFrame(i));
480  elapsedTimeSinceLastPacketSentSec = 0;
481  }
482 
483  // Compute time spent with processing one frame in this round
484  double computationTimeMs = (vtkIGSIOAccurateTimer::GetSystemTime() - startTimeSec) * 1000.0;
485 
486  // Update last processing time if new tracked frames have been acquired
487  if (trackedFrameList->GetNumberOfTrackedFrames() > 0)
488  {
489  self.LastProcessingTimePerFrameMs = computationTimeMs / trackedFrameList->GetNumberOfTrackedFrames();
490  }
491  return PLUS_SUCCESS;
492 }
493 
494 //----------------------------------------------------------------------------
496 {
497  igsioLockGuard<vtkIGSIORecursiveCriticalSection> mutexGuardedLock(self.MessageResponseQueueMutex);
498  if (!self.MessageResponseQueue.empty())
499  {
500  for (ClientIdToMessageListMap::iterator it = self.MessageResponseQueue.begin(); it != self.MessageResponseQueue.end(); ++it)
501  {
502  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self.IgtlClientsMutex);
503  igtl::ClientSocket::Pointer clientSocket = NULL;
504 
505  for (std::list<ClientData>::iterator clientIterator = self.IgtlClients.begin(); clientIterator != self.IgtlClients.end(); ++clientIterator)
506  {
507  if (clientIterator->ClientId == it->first)
508  {
509  clientSocket = clientIterator->ClientSocket;
510  break;
511  }
512  }
513  if (clientSocket.IsNull())
514  {
515  LOG_WARNING("Message reply cannot be sent to client " << it->first << ", probably client has been disconnected.");
516  continue;
517  }
518 
519  for (std::vector<igtl::MessageBase::Pointer>::iterator messageIt = it->second.begin(); messageIt != it->second.end(); ++messageIt)
520  {
521  clientSocket->Send((*messageIt)->GetBufferPointer(), (*messageIt)->GetBufferSize());
522  }
523  }
524  self.MessageResponseQueue.clear();
525  }
526 
527  return PLUS_SUCCESS;
528 }
529 
530 //----------------------------------------------------------------------------
532 {
533  PlusCommandResponseList replies;
534  self.PlusCommandProcessor->PopCommandResponses(replies);
535  if (!replies.empty())
536  {
537  for (PlusCommandResponseList::iterator responseIt = replies.begin(); responseIt != replies.end(); responseIt++)
538  {
539  igtl::MessageBase::Pointer igtlResponseMessage = self.CreateIgtlMessageFromCommandResponse(*responseIt);
540  if (igtlResponseMessage.IsNull())
541  {
542  LOG_ERROR("Failed to create OpenIGTLink message from command response");
543  continue;
544  }
545  igtlResponseMessage->Pack();
546 
547  // Only send the response to the client that requested the command
548  LOG_DEBUG("Send command reply to client " << (*responseIt)->GetClientId() << ": " << igtlResponseMessage->GetDeviceName());
549  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self.IgtlClientsMutex);
550  igtl::ClientSocket::Pointer clientSocket = NULL;
551  for (std::list<ClientData>::iterator clientIterator = self.IgtlClients.begin(); clientIterator != self.IgtlClients.end(); ++clientIterator)
552  {
553  if (clientIterator->ClientId == (*responseIt)->GetClientId())
554  {
555  clientSocket = clientIterator->ClientSocket;
556  break;
557  }
558  }
559 
560  if (clientSocket.IsNull())
561  {
562  LOG_WARNING("Message reply cannot be sent to client " << (*responseIt)->GetClientId() << ", probably client has been disconnected");
563  continue;
564  }
565  clientSocket->Send(igtlResponseMessage->GetBufferPointer(), igtlResponseMessage->GetBufferSize());
566  }
567  }
568 
569  return PLUS_SUCCESS;
570 }
571 
572 //----------------------------------------------------------------------------
573 void* vtkPlusOpenIGTLinkServer::DataReceiverThread(vtkMultiThreader::ThreadInfo* data)
574 {
575  ClientData* client = (ClientData*)(data->UserData);
576  client->DataReceiverActive.second = true;
577  vtkPlusOpenIGTLinkServer* self = client->Server;
578 
580  std::deque<uint32_t> previousCommandIds;
581 
582  // Make copy of frequently used data to avoid locking of client data
583  igtl::ClientSocket::Pointer clientSocket = client->ClientSocket;
584  int clientId = client->ClientId;
585 
586  igtl::MessageHeader::Pointer headerMsg = self->IgtlMessageFactory->CreateHeaderMessage(IGTL_HEADER_VERSION_1);
587 
588  while (client->DataReceiverActive.first)
589  {
590  headerMsg->InitBuffer();
591 
592  // Receive generic header from the socket
593  bool timeout(false);
594  igtlUint64 bytesReceived = clientSocket->Receive(headerMsg->GetBufferPointer(), headerMsg->GetBufferSize(), timeout);
595  if (bytesReceived == IGTL_EMPTY_DATA_SIZE || bytesReceived != headerMsg->GetBufferSize())
596  {
597  vtkIGSIOAccurateTimer::Delay(0.1);
598  continue;
599  }
600 
601  headerMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
602 
603  {
604  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self->IgtlClientsMutex);
605  // Keep track of the highest known version of message ever sent by this client, this is the version that we reply with
606  // (upper bounded by the servers version)
607  if (headerMsg->GetHeaderVersion() > client->ClientInfo.GetClientHeaderVersion())
608  {
609  client->ClientInfo.SetClientHeaderVersion(std::min<int>(self->GetIGTLHeaderVersion(), headerMsg->GetHeaderVersion()));
610  }
611  }
612 
613  igtl::MessageBase::Pointer bodyMessage = self->IgtlMessageFactory->CreateReceiveMessage(headerMsg);
614  if (bodyMessage.IsNull())
615  {
616  LOG_ERROR("Unable to receive message from client: " << client->ClientId);
617  continue;
618  }
619 
620  if (typeid(*bodyMessage) == typeid(igtl::PlusClientInfoMessage))
621  {
622  igtl::PlusClientInfoMessage::Pointer clientInfoMsg = dynamic_cast<igtl::PlusClientInfoMessage*>(bodyMessage.GetPointer());
623  clientInfoMsg->SetMessageHeader(headerMsg);
624  clientInfoMsg->AllocateBuffer();
625 
626  bool timeout(false);
627  clientSocket->Receive(clientInfoMsg->GetBufferBodyPointer(), clientInfoMsg->GetBufferBodySize(), timeout);
628 
629  int c = clientInfoMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
630  if (c & igtl::MessageHeader::UNPACK_BODY || clientInfoMsg->GetBufferBodySize() == 0)
631  {
632  // Message received from client, need to lock to modify client info
633  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(self->IgtlClientsMutex);
634  client->ClientInfo = clientInfoMsg->GetClientInfo();
635  LOG_DEBUG("Client info message received from client " << clientId);
636  }
637  }
638  else if (typeid(*bodyMessage) == typeid(igtl::GetStatusMessage))
639  {
640  // Just ping server, we can skip message and respond
641  clientSocket->Skip(headerMsg->GetBodySizeToRead(), 0);
642 
643  igtl::StatusMessage::Pointer replyMsg = dynamic_cast<igtl::StatusMessage*>(self->IgtlMessageFactory->CreateSendMessage("STATUS", client->ClientInfo.GetClientHeaderVersion()).GetPointer());
644  replyMsg->SetCode(igtl::StatusMessage::STATUS_OK);
645  replyMsg->Pack();
646  clientSocket->Send(replyMsg->GetBufferPointer(), replyMsg->GetBufferSize());
647  }
648  else if (typeid(*bodyMessage) == typeid(igtl::StringMessage)
649  && vtkPlusCommand::IsCommandDeviceName(headerMsg->GetDeviceName()))
650  {
651  igtl::StringMessage::Pointer stringMsg = dynamic_cast<igtl::StringMessage*>(bodyMessage.GetPointer());
652  stringMsg->SetMessageHeader(headerMsg);
653  stringMsg->AllocateBuffer();
654  bool timeout(false);
655  clientSocket->Receive(stringMsg->GetBufferBodyPointer(), stringMsg->GetBufferBodySize(), timeout);
656 
657  // We are receiving old style commands, handle it
658  int c = stringMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
659  if (c & igtl::MessageHeader::UNPACK_BODY || stringMsg->GetBufferBodySize() == 0)
660  {
661  std::string deviceName(headerMsg->GetDeviceName());
662  if (deviceName.empty())
663  {
664  self->PlusCommandProcessor->QueueStringResponse(PLUS_FAIL, std::string(vtkPlusCommand::DEVICE_NAME_REPLY), clientId, "Unable to read DeviceName.");
665  continue;
666  }
667 
668  uint32_t uid(0);
669  try
670  {
671 #if (_MSC_VER == 1500)
673  ss >> uid;
674 #else
676 #endif
677  }
678  catch (std::invalid_argument e)
679  {
680  LOG_ERROR("Unable to extract command UID from device name string.");
681  // Removing support for malformed command strings, reply with error
682  self->PlusCommandProcessor->QueueStringResponse(PLUS_FAIL, std::string(vtkPlusCommand::DEVICE_NAME_REPLY), clientId, "Malformed DeviceName. Expected CMD_cmdId (ex: CMD_001)");
683  continue;
684  }
685 
687 
688  if (std::find(previousCommandIds.begin(), previousCommandIds.end(), uid) != previousCommandIds.end())
689  {
690  // Command already exists
691  LOG_WARNING("Already received a command with id = " << uid << " from client " << clientId << ". This repeated command will be ignored.");
692  continue;
693  }
694  // New command, remember its ID
695  previousCommandIds.push_back(uid);
696  if (previousCommandIds.size() > NUMBER_OF_RECENT_COMMAND_IDS_STORED)
697  {
698  previousCommandIds.pop_front();
699  }
700 
701  LOG_DEBUG("Received command from client " << clientId << ", device " << deviceName << " with UID " << uid << ": " << stringMsg->GetString());
702 
703  vtkSmartPointer<vtkXMLDataElement> cmdElement = vtkSmartPointer<vtkXMLDataElement>::Take(vtkXMLUtilities::ReadElementFromString(stringMsg->GetString()));
704  std::string commandName = std::string(cmdElement->GetAttribute("Name") == NULL ? "" : cmdElement->GetAttribute("Name"));
705 
706  self->PlusCommandProcessor->QueueCommand(false, clientId, commandName, stringMsg->GetString(), deviceName, uid, stringMsg->GetMetaData());
707  }
708 
709  }
710  else if (typeid(*bodyMessage) == typeid(igtl::CommandMessage))
711  {
712  igtl::CommandMessage::Pointer commandMsg = dynamic_cast<igtl::CommandMessage*>(bodyMessage.GetPointer());
713  commandMsg->SetMessageHeader(headerMsg);
714  commandMsg->AllocateBuffer();
715  bool timeout(false);
716  void* bodyPointer(commandMsg->GetBufferBodyPointer());
717  igtlUint64 bodySize(commandMsg->GetBufferBodySize());
718 
719  igtlUint64 bytesReceived = clientSocket->Receive(bodyPointer, bodySize, timeout);
720  if (bytesReceived == IGTL_EMPTY_DATA_SIZE || bytesReceived != bodySize)
721  {
722  LOG_ERROR("Failed to receive command message from client " << clientId);
723  continue;
724  }
725 
726  int c = commandMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
727  if (c & igtl::MessageHeader::UNPACK_BODY || commandMsg->GetBufferBodySize() == 0)
728  {
729  std::string deviceName(headerMsg->GetDeviceName());
730 
731  uint32_t uid;
732  uid = commandMsg->GetCommandId();
733 
734  if (std::find(previousCommandIds.begin(), previousCommandIds.end(), uid) != previousCommandIds.end())
735  {
736  // Command already exists
737  LOG_WARNING("Already received a command with id = " << uid << " from client " << clientId << ". This repeated command will be ignored.");
738  continue;
739  }
740  // New command, remember its ID
741  previousCommandIds.push_back(uid);
742  if (previousCommandIds.size() > NUMBER_OF_RECENT_COMMAND_IDS_STORED)
743  {
744  previousCommandIds.pop_front();
745  }
746 
747  LOG_DEBUG("Received header version " << commandMsg->GetHeaderVersion() << " command " << commandMsg->GetCommandName()
748  << " from client " << clientId << ", device " << deviceName << " with UID " << uid << ": " << commandMsg->GetCommandContent());
749 
750  self->PlusCommandProcessor->QueueCommand(true, clientId, commandMsg->GetCommandName(), commandMsg->GetCommandContent(), deviceName, uid, commandMsg->GetMetaData());
751  }
752  else
753  {
754  LOG_ERROR("STRING message unpacking failed for client " << clientId);
755  }
756  }
757  else if (typeid(*bodyMessage) == typeid(igtl::StartTrackingDataMessage))
758  {
759  std::string deviceName("");
760 
761  igtl::StartTrackingDataMessage::Pointer startTracking = dynamic_cast<igtl::StartTrackingDataMessage*>(bodyMessage.GetPointer());
762  startTracking->SetMessageHeader(headerMsg);
763  startTracking->AllocateBuffer();
764  bool timeout(false);
765  clientSocket->Receive(startTracking->GetBufferBodyPointer(), startTracking->GetBufferBodySize(), timeout);
766 
767  int c = startTracking->Unpack(self->IgtlMessageCrcCheckEnabled);
768  if (c & igtl::MessageHeader::UNPACK_BODY || startTracking->GetBufferBodySize() == 0)
769  {
770  client->ClientInfo.SetTDATAResolution(startTracking->GetResolution());
771  client->ClientInfo.SetTDATARequested(true);
772  }
773  else
774  {
775  LOG_ERROR("Client " << clientId << " STT_TDATA failed: could not retrieve startTracking message");
776  return NULL;
777  }
778 
779  igtl::MessageBase::Pointer msg = self->IgtlMessageFactory->CreateSendMessage("RTS_TDATA", client->ClientInfo.GetClientHeaderVersion());
780  igtl::RTSTrackingDataMessage* rtsMsg = dynamic_cast<igtl::RTSTrackingDataMessage*>(msg.GetPointer());
781  rtsMsg->SetStatus(0);
782  rtsMsg->Pack();
783  self->QueueMessageResponseForClient(client->ClientId, msg);
784  }
785  else if (typeid(*bodyMessage) == typeid(igtl::StopTrackingDataMessage))
786  {
787  igtl::StopTrackingDataMessage::Pointer stopTracking = dynamic_cast<igtl::StopTrackingDataMessage*>(bodyMessage.GetPointer());
788  stopTracking->SetMessageHeader(headerMsg);
789  stopTracking->AllocateBuffer();
790  bool timeout(false);
791  clientSocket->Receive(stopTracking->GetBufferBodyPointer(), stopTracking->GetBufferBodySize(), timeout);
792 
793  client->ClientInfo.SetTDATARequested(false);
794  igtl::MessageBase::Pointer msg = self->IgtlMessageFactory->CreateSendMessage("RTS_TDATA", client->ClientInfo.GetClientHeaderVersion());
795  igtl::RTSTrackingDataMessage* rtsMsg = dynamic_cast<igtl::RTSTrackingDataMessage*>(msg.GetPointer());
796  rtsMsg->SetStatus(0);
797  rtsMsg->Pack();
798  self->QueueMessageResponseForClient(client->ClientId, msg);
799  }
800  else if (typeid(*bodyMessage) == typeid(igtl::GetPolyDataMessage))
801  {
802  igtl::GetPolyDataMessage::Pointer polyDataMessage = dynamic_cast<igtl::GetPolyDataMessage*>(bodyMessage.GetPointer());
803  polyDataMessage->SetMessageHeader(headerMsg);
804  polyDataMessage->AllocateBuffer();
805  bool timeout(false);
806  clientSocket->Receive(polyDataMessage->GetBufferBodyPointer(), polyDataMessage->GetBufferBodySize(), timeout);
807 
808  int c = polyDataMessage->Unpack(self->IgtlMessageCrcCheckEnabled);
809  if (c & igtl::MessageHeader::UNPACK_BODY || polyDataMessage->GetBufferBodySize() == 0)
810  {
811  std::string fileName;
812  // Check metadata for requisite parameters, if absent, check deviceName
813  if (polyDataMessage->GetHeaderVersion() > IGTL_HEADER_VERSION_1)
814  {
815  if (!polyDataMessage->GetMetaDataElement("filename", fileName))
816  {
817  fileName = polyDataMessage->GetDeviceName();
818  if (fileName.empty())
819  {
820  LOG_ERROR("GetPolyData message sent with no filename in either metadata or deviceName field.");
821  continue;
822  }
823  }
824  }
825  else
826  {
827  fileName = polyDataMessage->GetDeviceName();
828  if (fileName.empty())
829  {
830  LOG_ERROR("GetPolyData message sent with no filename in either metadata or deviceName field.");
831  continue;
832  }
833  }
834 
835  vtkSmartPointer<vtkPolyDataReader> reader = vtkSmartPointer<vtkPolyDataReader>::New();
836  reader->SetFileName(fileName.c_str());
837  reader->Update();
838 
839  auto polyData = reader->GetOutput();
840  if (polyData != nullptr)
841  {
842  igtl::MessageBase::Pointer msg = self->IgtlMessageFactory->CreateSendMessage("POLYDATA", client->ClientInfo.GetClientHeaderVersion());
843  igtl::PolyDataMessage* polyMsg = dynamic_cast<igtl::PolyDataMessage*>(msg.GetPointer());
844 
845  igtlioPolyDataConverter::ContentData data;
846  data.deviceName = "PlusServer";
847  data.polydata = polyData;
848 
849  igtlioBaseConverter::HeaderData header;
850  header.deviceName = "PlusServer";
851 
852  igtlioPolyDataConverter::toIGTL(header, data, (igtl::PolyDataMessage::Pointer*)&msg);
853  if (!msg->SetMetaDataElement("fileName", IANA_TYPE_US_ASCII, fileName))
854  {
855  LOG_ERROR("Filename too long to be sent back to client. Aborting.");
856  continue;
857  }
858  self->QueueMessageResponseForClient(client->ClientId, msg);
859  continue;
860  }
861 
862  igtl::MessageBase::Pointer msg = self->IgtlMessageFactory->CreateSendMessage("RTS_POLYDATA", polyDataMessage->GetHeaderVersion());
863  igtl::RTSPolyDataMessage* rtsPolyMsg = dynamic_cast<igtl::RTSPolyDataMessage*>(msg.GetPointer());
864  rtsPolyMsg->SetStatus(false);
865  self->QueueMessageResponseForClient(client->ClientId, rtsPolyMsg);
866  }
867  else
868  {
869  LOG_ERROR("Client " << clientId << " GET_POLYDATA failed: could not retrieve message");
870  return NULL;
871  }
872  }
873  else if (typeid(*bodyMessage) == typeid(igtl::StatusMessage))
874  {
875  // status message is used as a keep-alive, don't do anything
876  clientSocket->Skip(headerMsg->GetBodySizeToRead(), 0);
877  }
878  else if (typeid(*bodyMessage) == typeid(igtl::GetImageMetaMessage))
879  {
880  igtl::GetImageMetaMessage::Pointer getImageMetaMsg = dynamic_cast<igtl::GetImageMetaMessage*>(bodyMessage.GetPointer());
881  getImageMetaMsg->SetMessageHeader(headerMsg);
882  getImageMetaMsg->AllocateBuffer();
883  bool timeout(false);
884  clientSocket->Receive(getImageMetaMsg->GetBufferBodyPointer(), getImageMetaMsg->GetBufferBodySize(), timeout);
885 
886  int c = getImageMetaMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
887  if (c & igtl::MessageHeader::UNPACK_BODY || getImageMetaMsg->GetBufferBodySize() == 0)
888  {
889  // Image meta message
890  std::string deviceName("");
891  if (headerMsg->GetDeviceName() != NULL)
892  {
893  deviceName = headerMsg->GetDeviceName();
894  }
895  self->PlusCommandProcessor->QueueGetImageMetaData(clientId, deviceName);
896  }
897  else
898  {
899  LOG_ERROR("Client " << clientId << " GET_IMGMETA failed: could not retrieve message");
900  return NULL;
901  }
902  }
903  else if (typeid(*bodyMessage) == typeid(igtl::GetImageMessage))
904  {
905  igtl::GetImageMessage::Pointer getImageMsg = dynamic_cast<igtl::GetImageMessage*>(bodyMessage.GetPointer());
906  getImageMsg->SetMessageHeader(headerMsg);
907  getImageMsg->AllocateBuffer();
908  bool timeout(false);
909  clientSocket->Receive(getImageMsg->GetBufferBodyPointer(), getImageMsg->GetBufferBodySize(), timeout);
910 
911  int c = getImageMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
912  if (c & igtl::MessageHeader::UNPACK_BODY || getImageMsg->GetBufferBodySize() == 0)
913  {
914  std::string deviceName("");
915  if (headerMsg->GetDeviceName() != NULL)
916  {
917  deviceName = headerMsg->GetDeviceName();
918  }
919  else
920  {
921  LOG_ERROR("Please select the image you want to acquire");
922  return NULL;
923  }
924  self->PlusCommandProcessor->QueueGetImage(clientId, deviceName);
925  }
926  else
927  {
928  LOG_ERROR("Client " << clientId << " GET_IMAGE failed: could not retrieve message");
929  return NULL;
930  }
931 
932  }
933  else if (typeid(*bodyMessage) == typeid(igtl::GetPointMessage))
934  {
935  igtl::GetPointMessage* getPointMsg = dynamic_cast<igtl::GetPointMessage*>(bodyMessage.GetPointer());
936  getPointMsg->SetMessageHeader(headerMsg);
937  getPointMsg->AllocateBuffer();
938  bool timeout(false);
939  clientSocket->Receive(getPointMsg->GetBufferBodyPointer(), getPointMsg->GetBufferBodySize(), timeout);
940 
941  int c = getPointMsg->Unpack(self->IgtlMessageCrcCheckEnabled);
942  if (c & igtl::MessageHeader::UNPACK_BODY || getPointMsg->GetBufferBodySize() == 0)
943  {
944  std::string fileName;
945  if (!getPointMsg->GetMetaDataElement("Filename", fileName))
946  {
947  fileName = getPointMsg->GetDeviceName();
948  }
949 
950  if (igsioCommon::Tail(fileName, 4) != "fcsv")
951  {
952  LOG_WARNING("Filename does not end in fcsv. GetPoint behaviour may not function correctly.");
953  }
954 
955  if (!vtksys::SystemTools::FileExists(fileName) &&
956  !vtksys::SystemTools::FileExists(vtkPlusConfig::GetInstance()->GetImagePath(fileName)))
957  {
958  LOG_ERROR("File: " << fileName << " requested but does not exist. Cannot get POINT data from it.");
959  return NULL;
960  }
961 
962  igtl::MessageBase::Pointer msg = self->IgtlMessageFactory->CreateSendMessage("POINT", client->ClientInfo.GetClientHeaderVersion());
963  igtl::PointMessage* pointMsg = dynamic_cast<igtl::PointMessage*>(msg.GetPointer());
964 
965  std::ifstream t(fileName);
966  if (!t.is_open())
967  {
968  t.open(vtkPlusConfig::GetInstance()->GetImagePath(fileName));
969  if (!t.is_open())
970  {
971  LOG_ERROR("Cannot read file: " << fileName);
972  return NULL;
973  }
974  }
975  std::stringstream buffer;
976  buffer << t.rdbuf();
977  std::vector<std::string> lines = igsioCommon::SplitStringIntoTokens(buffer.str(), '\n', false);
978  for (std::vector<std::string>::iterator it = lines.begin(); it != lines.end(); ++it)
979  {
980  std::string line = igsioCommon::Trim(*it);
981  if (line[0] == '#')
982  {
983  continue;
984  }
985 
986  std::vector<std::string> tokens = igsioCommon::SplitStringIntoTokens(line, ',', true);
987  igtl::PointElement::Pointer elem = igtl::PointElement::New();
988  elem->SetPosition(std::stof(tokens[1]), std::stof(tokens[2]), std::stof(tokens[3]));
989  elem->SetName(tokens[0].c_str());
990  elem->SetGroupName("Point");
991  pointMsg->AddPointElement(elem);
992  }
993 
994  self->QueueMessageResponseForClient(client->ClientId, pointMsg);
995  }
996  else
997  {
998  LOG_ERROR("Client " << clientId << " GET_POINT failed: could not retrieve message");
999  return NULL;
1000  }
1001  }
1002  else
1003  {
1004  // if the device type is unknown, skip reading.
1005  LOG_WARNING("Unknown OpenIGTLink message is received from client " << clientId << ". Device type: " << headerMsg->GetMessageType()
1006  << ". Device name: " << headerMsg->GetDeviceName() << ".");
1007  clientSocket->Skip(headerMsg->GetBodySizeToRead(), 0);
1008  continue;
1009  }
1010  } // ConnectionActive
1011 
1012  // Close thread
1013  client->DataReceiverActive.second = false;
1014  return NULL;
1015 }
1016 
1017 //----------------------------------------------------------------------------
1019 {
1020  int numberOfErrors = 0;
1021 
1022  // Update transform repository with the tracked frame
1023  if (this->TransformRepository != NULL)
1024  {
1025  if (this->TransformRepository->SetTransforms(trackedFrame) != PLUS_SUCCESS)
1026  {
1027  LOG_ERROR("Failed to set current transforms to transform repository");
1028  numberOfErrors++;
1029  }
1030  }
1031 
1032  // Convert relative timestamp to UTC
1033  double timestampSystem = trackedFrame.GetTimestamp(); // save original timestamp, we'll restore it later
1034  double timestampUniversal = vtkIGSIOAccurateTimer::GetUniversalTimeFromSystemTime(timestampSystem);
1035  trackedFrame.SetTimestamp(timestampUniversal);
1036 
1037  std::vector<int> disconnectedClientIds;
1038  {
1039  // Lock before we send message to the clients
1040  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1041  if (this->NewClientConnected)
1042  {
1043  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1044  {
1045  std::vector<PlusIgtlClientInfo::VideoStream> videoStreams = (*clientIterator).ClientInfo.VideoStreams;
1046  for (std::vector<PlusIgtlClientInfo::VideoStream>::iterator videoStream = videoStreams.begin(); videoStream != videoStreams.end(); ++videoStream)
1047  {
1048  vtkIGSIOFrameConverter* frameConverter = videoStream->FrameConverter;
1049  if (frameConverter)
1050  {
1051  frameConverter->RequestKeyFrameOn();
1052  }
1053  }
1054  }
1055  }
1056  this->NewClientConnected = false;
1057 
1058  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1059  {
1060  igtl::ClientSocket::Pointer clientSocket = (*clientIterator).ClientSocket;
1061 
1062  // Create IGT messages
1063  std::vector<igtl::MessageBase::Pointer> igtlMessages;
1064  std::vector<igtl::MessageBase::Pointer>::iterator igtlMessageIterator;
1065 
1066  if (this->IgtlMessageFactory->PackMessages(clientIterator->ClientId, clientIterator->ClientInfo, igtlMessages, trackedFrame, this->SendValidTransformsOnly, this->TransformRepository) != PLUS_SUCCESS)
1067  {
1068  LOG_WARNING("Failed to pack all IGT messages");
1069  }
1070 
1071  // Send all messages to a client
1072  for (igtlMessageIterator = igtlMessages.begin(); igtlMessageIterator != igtlMessages.end(); ++igtlMessageIterator)
1073  {
1074  igtl::MessageBase::Pointer igtlMessage = (*igtlMessageIterator);
1075  if (igtlMessage.IsNull())
1076  {
1077  continue;
1078  }
1079 
1080  int retValue = 0;
1081  RETRY_UNTIL_TRUE((retValue = clientSocket->Send(igtlMessage->GetBufferPointer(), igtlMessage->GetBufferSize())) != 0, this->NumberOfRetryAttempts, this->DelayBetweenRetryAttemptsSec);
1082  if (retValue == 0)
1083  {
1084  disconnectedClientIds.push_back(clientIterator->ClientId);
1085  auto ts = igtl::TimeStamp::New();
1086  igtlMessage->GetTimeStamp(ts);
1087  LOG_INFO("Client disconnected - could not send " << igtlMessage->GetMessageType() << " message to client (device name: " << igtlMessage->GetDeviceName()
1088  << " Timestamp: " << std::fixed << ts->GetTimeStamp() << ").");
1089  break;
1090  }
1091 
1092  // Update the TDATA timestamp, even if TDATA isn't sent (cheaper than checking for existing TDATA message type)
1093  clientIterator->ClientInfo.SetLastTDATASentTimeStamp(trackedFrame.GetTimestamp());
1094  }
1095  }
1096  }
1097 
1098  // Clean up disconnected clients
1099  for (std::vector< int >::iterator it = disconnectedClientIds.begin(); it != disconnectedClientIds.end(); ++it)
1100  {
1101  DisconnectClient(*it);
1102  }
1103 
1104  // restore original timestamp
1105  trackedFrame.SetTimestamp(timestampSystem);
1106 
1107  return (numberOfErrors == 0 ? PLUS_SUCCESS : PLUS_FAIL);
1108 }
1109 
1110 //----------------------------------------------------------------------------
1112 {
1113  // Stop the client's data receiver thread
1114  {
1115  // Request thread stop
1116  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1117  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1118  {
1119  if (clientIterator->ClientId != clientId)
1120  {
1121  continue;
1122  }
1123  clientIterator->DataReceiverActive.first = false;
1124  break;
1125  }
1126  }
1127 
1128  // Wait for the thread to stop
1129  bool clientDataReceiverThreadStillActive = false;
1130  do
1131  {
1132  clientDataReceiverThreadStillActive = false;
1133  {
1134  // check if any of the receiver threads are still active
1135  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1136  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1137  {
1138  if (clientIterator->ClientId != clientId)
1139  {
1140  continue;
1141  }
1142  if (clientIterator->DataReceiverThreadId >= 0)
1143  {
1144  if (clientIterator->DataReceiverActive.second)
1145  {
1146  // thread still running
1147  clientDataReceiverThreadStillActive = true;
1148  }
1149  else
1150  {
1151  // thread stopped
1152  // We still need to call vtkMultiThreader::TerminateThread, not to terminate the thread (as it is already stopped)
1153  // but to indicate to the multithreader that the thread ID can be reused. Without this, vtkMultiThreader runs out
1154  // of usable thread IDs after the number of connects/disconnects reaches VTK_MAX_THREADS
1155  this->Threader->TerminateThread(clientIterator->DataReceiverThreadId);
1156  clientIterator->DataReceiverThreadId = -1;
1157  }
1158  break;
1159  }
1160  }
1161  }
1162  if (clientDataReceiverThreadStillActive)
1163  {
1164  // give some time for the threads to finish
1165  vtkIGSIOAccurateTimer::DelayWithEventProcessing(0.2);
1166  }
1167  }
1168  while (clientDataReceiverThreadStillActive);
1169 
1170  // Close socket and remove client from the list
1171  int port = 0;
1172  std::string address = "unknown";
1173  {
1174  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1175  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1176  {
1177  if (clientIterator->ClientId != clientId)
1178  {
1179  continue;
1180  }
1181  if (clientIterator->ClientSocket.IsNotNull())
1182  {
1183 #if (OPENIGTLINK_VERSION_MAJOR > 1) || ( OPENIGTLINK_VERSION_MAJOR == 1 && OPENIGTLINK_VERSION_MINOR > 9 ) || ( OPENIGTLINK_VERSION_MAJOR == 1 && OPENIGTLINK_VERSION_MINOR == 9 && OPENIGTLINK_VERSION_PATCH > 4 )
1184  clientIterator->ClientSocket->GetSocketAddressAndPort(address, port);
1185 #endif
1186  clientIterator->ClientSocket->CloseSocket();
1187  }
1188  this->IgtlClients.erase(clientIterator);
1189  break;
1190  }
1191  }
1192 
1193  LOG_INFO("Client disconnected (" << address << ":" << port << "). Number of connected clients: " << GetNumberOfConnectedClients());
1194 }
1195 
1196 //----------------------------------------------------------------------------
1198 {
1199  LOG_TRACE("Keep alive packet sent to clients...");
1200 
1201  std::vector< int > disconnectedClientIds;
1202 
1203  {
1204  // Lock before we send message to the clients
1205  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1206 
1207  for (std::list<ClientData>::iterator clientIterator = this->IgtlClients.begin(); clientIterator != this->IgtlClients.end(); ++clientIterator)
1208  {
1209  auto replyMsg = igtl::StatusMessage::New();
1210  replyMsg->SetCode(igtl::StatusMessage::STATUS_OK);
1211  replyMsg->Pack();
1212 
1213  int retValue = 0;
1214  RETRY_UNTIL_TRUE(
1215  (retValue = clientIterator->ClientSocket->Send(replyMsg->GetPackPointer(), replyMsg->GetPackSize())) != 0,
1216  this->NumberOfRetryAttempts, this->DelayBetweenRetryAttemptsSec);
1217  if (retValue == 0)
1218  {
1219  disconnectedClientIds.push_back(clientIterator->ClientId);
1220  auto ts = igtl::TimeStamp::New();
1221  replyMsg->GetTimeStamp(ts);
1222 
1223  LOG_DEBUG("Client disconnected - could not send " << replyMsg->GetMessageType() << " message to client (device name: " << replyMsg->GetDeviceName()
1224  << " Timestamp: " << std::fixed << ts->GetTimeStamp() << ").");
1225  }
1226  } // clientIterator
1227  } // unlock client list
1228 
1229  // Clean up disconnected clients
1230  for (std::vector< int >::iterator it = disconnectedClientIds.begin(); it != disconnectedClientIds.end(); ++it)
1231  {
1232  DisconnectClient(*it);
1233  }
1234 }
1235 
1236 //------------------------------------------------------------------------------
1238 {
1239  // Lock before we send message to the clients
1240  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1241  return this->IgtlClients.size();
1242 }
1243 
1244 //------------------------------------------------------------------------------
1245 PlusStatus vtkPlusOpenIGTLinkServer::GetClientInfo(unsigned int clientId, PlusIgtlClientInfo& outClientInfo) const
1246 {
1247  igsioLockGuard<vtkIGSIORecursiveCriticalSection> igtlClientsMutexGuardedLock(this->IgtlClientsMutex);
1248  for (std::list<ClientData>::const_iterator it = this->IgtlClients.begin(); it != this->IgtlClients.end(); ++it)
1249  {
1250  if (it->ClientId == clientId)
1251  {
1252  outClientInfo = it->ClientInfo;
1253  return PLUS_SUCCESS;
1254  }
1255  }
1256 
1257  return PLUS_FAIL;
1258 }
1259 
1260 //------------------------------------------------------------------------------
1261 PlusStatus vtkPlusOpenIGTLinkServer::ReadConfiguration(vtkXMLDataElement* serverElement, const std::string& aFilename)
1262 {
1263  LOG_TRACE("vtkPlusOpenIGTLinkServer::ReadConfiguration");
1264 
1265  if (aFilename.empty())
1266  {
1267  LOG_ERROR("Unable to configure PlusServer without an acceptable config file submitted.");
1268  return PLUS_FAIL;
1269  }
1270  this->SetConfigFilename(aFilename);
1271 
1272  XML_READ_SCALAR_ATTRIBUTE_REQUIRED(int, ListeningPort, serverElement);
1273  XML_READ_STRING_ATTRIBUTE_REQUIRED(OutputChannelId, serverElement);
1274  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, MissingInputGracePeriodSec, serverElement);
1275  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, MaxTimeSpentWithProcessingMs, serverElement);
1276  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, MaxNumberOfIgtlMessagesToSend, serverElement);
1277  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(int, NumberOfRetryAttempts, serverElement);
1278  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, DelayBetweenRetryAttemptsSec, serverElement);
1279  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, KeepAliveIntervalSec, serverElement);
1280  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(SendValidTransformsOnly, serverElement);
1281  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(IgtlMessageCrcCheckEnabled, serverElement);
1282  XML_READ_BOOL_ATTRIBUTE_OPTIONAL(LogWarningOnNoDataAvailable, serverElement);
1283 
1284  this->DefaultClientInfo.IgtlMessageTypes.clear();
1285  this->DefaultClientInfo.TransformNames.clear();
1286  this->DefaultClientInfo.ImageStreams.clear();
1287  this->DefaultClientInfo.VideoStreams.clear();
1288  this->DefaultClientInfo.StringNames.clear();
1289  this->DefaultClientInfo.SetTDATAResolution(0);
1290  this->DefaultClientInfo.SetTDATARequested(false);
1291 
1292  vtkXMLDataElement* defaultClientInfo = serverElement->FindNestedElementWithName("DefaultClientInfo");
1293  if (defaultClientInfo != NULL)
1294  {
1295  if (this->DefaultClientInfo.SetClientInfoFromXmlData(defaultClientInfo) != PLUS_SUCCESS)
1296  {
1297  return PLUS_FAIL;
1298  }
1299  }
1300 
1301  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(float, DefaultClientSendTimeoutSec, serverElement);
1302  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(float, DefaultClientReceiveTimeoutSec, serverElement);
1303 
1304  return PLUS_SUCCESS;
1305 }
1306 
1307 //------------------------------------------------------------------------------
1309 {
1310  return this->PlusCommandProcessor->ExecuteCommands();
1311 }
1312 
1313 //------------------------------------------------------------------------------
1315 {
1316  return (vtkIGSIOAccurateTimer::GetSystemTime() - this->BroadcastStartTime) > this->MissingInputGracePeriodSec;
1317 }
1318 
1319 //------------------------------------------------------------------------------
1320 PlusStatus vtkPlusOpenIGTLinkServer::Start(vtkPlusDataCollector* dataCollector, vtkIGSIOTransformRepository* transformRepository, vtkXMLDataElement* serverElement, const std::string& configFilePath)
1321 {
1322  if (serverElement == NULL)
1323  {
1324  LOG_ERROR("NULL configuration sent to vtkPlusOpenIGTLinkServer::Start. Unable to start PlusServer.");
1325  return PLUS_FAIL;
1326  }
1327 
1328  this->SetDataCollector(dataCollector);
1329  if (this->ReadConfiguration(serverElement, configFilePath.c_str()) != PLUS_SUCCESS)
1330  {
1331  LOG_ERROR("Failed to read PlusOpenIGTLinkServer configuration");
1332  return PLUS_FAIL;
1333  }
1334 
1335  this->SetTransformRepository(transformRepository);
1336  if (this->StartOpenIGTLinkService() != PLUS_SUCCESS)
1337  {
1338  LOG_ERROR("Failed to start Plus OpenIGTLink server");
1339  return PLUS_FAIL;
1340  }
1341 
1342  return PLUS_SUCCESS;
1343 }
1344 
1345 //------------------------------------------------------------------------------
1347 {
1348  PlusStatus status = PLUS_SUCCESS;
1349 
1351  {
1352  status = PLUS_FAIL;
1353  }
1354 
1355  SetDataCollector(NULL);
1356 
1357  SetTransformRepository(NULL);
1358 
1359  return status;
1360 }
1361 
1362 //------------------------------------------------------------------------------
1364 {
1365  int replyHeaderVersion = IGTL_HEADER_VERSION_1;
1366  PlusIgtlClientInfo info;
1367  if (GetClientInfo(response->GetClientId(), info) == PLUS_FAIL)
1368  {
1369  LOG_ERROR("Unable to find client with ID: " << response->GetClientId());
1370  }
1371  else
1372  {
1373  replyHeaderVersion = info.GetClientHeaderVersion();
1374  }
1376  if (stringResponse)
1377  {
1378  igtl::StringMessage::Pointer igtlMessage = dynamic_cast<igtl::StringMessage*>(this->IgtlMessageFactory->CreateSendMessage("STRING", replyHeaderVersion).GetPointer());
1379  igtlMessage->SetDeviceName(stringResponse->GetDeviceName().c_str());
1380  igtlMessage->SetString(stringResponse->GetMessage());
1381  LOG_DEBUG("String response: " << stringResponse->GetMessage());
1382  return igtlMessage.GetPointer();
1383  }
1384 
1386  if (imageResponse)
1387  {
1388  std::string imageName = imageResponse->GetImageName();
1389  if (imageName.empty())
1390  {
1391  imageName = "PlusServerImage";
1392  }
1393 
1394  vtkSmartPointer<vtkMatrix4x4> imageToReferenceTransform = vtkSmartPointer<vtkMatrix4x4>::New();
1395  if (imageResponse->GetImageToReferenceTransform() != NULL)
1396  {
1397  imageToReferenceTransform = imageResponse->GetImageToReferenceTransform();
1398  }
1399 
1400  vtkImageData* imageData = imageResponse->GetImageData();
1401  if (imageData == NULL)
1402  {
1403  LOG_ERROR("Invalid image data in command response");
1404  return NULL;
1405  }
1406 
1407  igtl::ImageMessage::Pointer igtlMessage = dynamic_cast<igtl::ImageMessage*>(this->IgtlMessageFactory->CreateSendMessage("IMAGE", replyHeaderVersion).GetPointer());
1408  igtlMessage->SetDeviceName(imageName.c_str());
1409 
1410  if (vtkPlusIgtlMessageCommon::PackImageMessage(igtlMessage, imageData, *imageToReferenceTransform, vtkIGSIOAccurateTimer::GetSystemTime()) != PLUS_SUCCESS)
1411  {
1412  LOG_ERROR("Failed to create image mesage from command response");
1413  return NULL;
1414  }
1415  return igtlMessage.GetPointer();
1416  }
1417 
1419  if (polydataResponse)
1420  {
1421  std::string polydataName = polydataResponse->GetPolyDataName();
1422  if (polydataName.empty())
1423  {
1424  polydataName = "UnknownFile";
1425  }
1426 
1427  vtkSmartPointer<vtkPolyData> polyData = polydataResponse->GetPolyData();
1428  if (polyData == NULL)
1429  {
1430  LOG_ERROR("Missing polydata in command response");
1431  return NULL;
1432  }
1433 
1434  igtl::PolyDataMessage::Pointer igtlMessage = dynamic_cast<igtl::PolyDataMessage*>(this->IgtlMessageFactory->CreateSendMessage("POLYDATA", replyHeaderVersion).GetPointer());
1435  igtlMessage->SetDeviceName("PlusServer");
1436  igtlMessage->SetMetaDataElement("fileName", IANA_TYPE_US_ASCII, polydataName);
1437 
1438  if (vtkPlusIgtlMessageCommon::PackPolyDataMessage(igtlMessage, polyData, vtkIGSIOAccurateTimer::GetSystemTime()) != PLUS_SUCCESS)
1439  {
1440  LOG_ERROR("Failed to create polydata mesage from command response");
1441  return NULL;
1442  }
1443  return igtlMessage.GetPointer();
1444  }
1445 
1447  if (imageMetaDataResponse)
1448  {
1449  std::string imageMetaDataName = "PlusServerImageMetaData";
1450  igsioCommon::ImageMetaDataList imageMetaDataList;
1451  imageMetaDataResponse->GetImageMetaDataItems(imageMetaDataList);
1452  igtl::ImageMetaMessage::Pointer igtlMessage = dynamic_cast<igtl::ImageMetaMessage*>(this->IgtlMessageFactory->CreateSendMessage("IMGMETA", replyHeaderVersion).GetPointer());
1453  igtlMessage->SetDeviceName(imageMetaDataName.c_str());
1454  if (vtkPlusIgtlMessageCommon::PackImageMetaMessage(igtlMessage, imageMetaDataList) != PLUS_SUCCESS)
1455  {
1456  LOG_ERROR("Failed to create image mesage from command response");
1457  return NULL;
1458  }
1459  return igtlMessage.GetPointer();
1460  }
1461 
1463  if (commandResponse)
1464  {
1465  if (!commandResponse->GetRespondWithCommandMessage())
1466  {
1467  // Incoming command was a v1/v2 style command, reply as such
1468  igtl::StringMessage::Pointer igtlMessage = dynamic_cast<igtl::StringMessage*>(this->IgtlMessageFactory->CreateSendMessage("STRING", replyHeaderVersion).GetPointer());
1469  igtlMessage->SetDeviceName(vtkPlusCommand::GenerateReplyDeviceName(commandResponse->GetOriginalId()));
1470 
1471  std::ostringstream replyStr;
1472  replyStr << "<CommandReply";
1473  replyStr << " Status=\"" << (commandResponse->GetStatus() == PLUS_SUCCESS ? "SUCCESS" : "FAIL") << "\"";
1474  replyStr << " Message=\"";
1475  // Write to XML, encoding special characters, such as " ' \ < > &
1476  vtkXMLUtilities::EncodeString(commandResponse->GetResultString().c_str(), VTK_ENCODING_NONE, replyStr, VTK_ENCODING_NONE, 1 /* encode special characters */);
1477  replyStr << "\"";
1478  replyStr << " />";
1479 
1480  igtlMessage->SetString(replyStr.str().c_str());
1481  LOG_DEBUG("Command response: " << replyStr.str());
1482  return igtlMessage.GetPointer();
1483  }
1484  else
1485  {
1486  // Incoming command was a modern style command, reply using our latest
1487  igtl::RTSCommandMessage::Pointer igtlMessage = dynamic_cast<igtl::RTSCommandMessage*>(this->IgtlMessageFactory->CreateSendMessage("RTS_COMMAND", replyHeaderVersion).GetPointer());
1488  //TODO : should this device name be the name of the server?
1489  igtlMessage->SetDeviceName(commandResponse->GetDeviceName().c_str());
1490  igtlMessage->SetCommandName(commandResponse->GetCommandName());
1491  igtlMessage->SetCommandId(commandResponse->GetOriginalId());
1492 
1493  // Send command result details both in XML and in metadata, slowly phase towards metadata
1494  std::ostringstream replyStr;
1495  if (commandResponse->GetUseDefaultFormat())
1496  {
1497 
1498  replyStr << "<CommandReply";
1499  replyStr << " Name=\"" << commandResponse->GetCommandName() << "\"";
1500  replyStr << " Status=\"" << (commandResponse->GetStatus() ? "SUCCESS" : "FAIL") << "\"";
1501  if (commandResponse->GetStatus() == PLUS_FAIL)
1502  {
1503  replyStr << " Error=\"" << commandResponse->GetErrorString() << "\"";
1504  }
1505  replyStr << " Message=\"" << commandResponse->GetResultString() << "\"></CommandReply>";
1506  igtlMessage->SetMetaDataElement("Message", IANA_TYPE_US_ASCII, commandResponse->GetResultString());
1507  }
1508  else
1509  {
1510  replyStr << commandResponse->GetResultString();
1511  }
1512  igtlMessage->SetCommandContent(replyStr.str());
1513 
1514  for (igtl::MessageBase::MetaDataMap::const_iterator it = begin(commandResponse->GetParameters()); it != end(commandResponse->GetParameters()); ++it)
1515  {
1516  igtlMessage->SetMetaDataElement(it->first, it->second.first, it->second.second);
1517  }
1518 
1519  igtlMessage->SetMetaDataElement("Status", IANA_TYPE_US_ASCII, (commandResponse->GetStatus() ? "SUCCESS" : "FAIL"));
1520  if (commandResponse->GetStatus() == PLUS_FAIL)
1521  {
1522  igtlMessage->SetMetaDataElement("Error", IANA_TYPE_US_ASCII, commandResponse->GetErrorString());
1523  }
1524 
1525  LOG_DEBUG("Command response: " << replyStr.str());
1526  return igtlMessage.GetPointer();
1527  }
1528  }
1529 
1530  LOG_ERROR("vtkPlusOpenIGTLinkServer::CreateIgtlMessageFromCommandResponse failed: invalid command response");
1531  return NULL;
1532 }
static const double SAMPLING_SKIPPING_MARGIN_SEC
const uint32_t * data
Definition: phidget22.h:3971
static PlusStatus PackImageMessage(igtl::ImageMessage::Pointer imageMessage, igsioTrackedFrame &trackedFrame, const vtkMatrix4x4 &imageToReferenceTransform, vtkIGSIOFrameConverter *frameConverter=NULL)
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *serverElement, const std::string &aFilename)
static std::string GenerateReplyDeviceName(uint32_t uid)
bool HasVideoSource() const
Abstract interface for tracker and video devices.
Definition: vtkPlusDevice.h:60
static vtkPlusCommandImageMetaDataResponse * SafeDownCast(vtkObject *o)
static vtkPlusCommandStringResponse * SafeDownCast(vtkObject *o)
const char int line
Definition: phidget22.h:2458
static PlusStatus SendCommandResponses(vtkPlusOpenIGTLinkServer &self)
std::vector< ImageStream > ImageStreams
IGTL message helper class for PlusServer ClientInfo class.
Class to abstract away specific sequence file read/write details.
Definition: vtkPlusLogger.h:21
std::vector< std::string > IgtlMessageTypes
igsioStatus PlusStatus
Definition: PlusCommon.h:40
void PrintServerInfo(vtkPlusOpenIGTLinkServer *self)
void SetClientHeaderVersion(int version)
PlusStatus SetClientInfoFromXmlData(const char *strXmlData)
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
std::vector< std::string > StringNames
vtkSmartPointer< vtkIGSIOFrameConverter > FrameConverter
std::vector< vtkPlusDevice * > DeviceCollection
Definition: vtkPlusDevice.h:46
const igtl::MessageBase::MetaDataMap & GetParameters() const
PlusIgtlClientInfo ClientInfo
for i
std::vector< igsioTransformName > TransformNames
Creates a PlusCommand from a string. If the commands are to be executed on the main thread then call ...
virtual uint32_t GetOriginalId()
vtkPlusOpenIGTLinkServer * Server
#define PLUS_FAIL
Definition: PlusCommon.h:43
std::pair< bool, bool > DataReceiverActive
Active flag for thread (first: request, second: respond )
int port
Definition: phidget22.h:2454
static vtkPlusConfig * GetInstance()
int ClientId
Unique client identifier. First valid value is 1.
virtual std::string GetErrorString()
static PlusStatus SendMessageResponses(vtkPlusOpenIGTLinkServer &self)
virtual vtkMatrix4x4 * GetImageToReferenceTransform()
static PlusStatus PackImageMetaMessage(igtl::ImageMetaMessage::Pointer imageMetaMessage, igsioCommon::ImageMetaDataList &imageMetaDataList)
PlusStatus GetOutputChannelByName(vtkPlusChannel *&aChannel, const char *aChannelId)
virtual PlusStatus SendTrackedFrame(igsioTrackedFrame &trackedFrame)
virtual std::string GetMessage()
Manages devices that record image or positional data.
const char ** deviceName
Definition: phidget22.h:1316
virtual PlusStatus GetClientInfo(unsigned int clientId, PlusIgtlClientInfo &outClientInfo) const
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
PlusStatus Start(vtkPlusDataCollector *dataCollector, vtkIGSIOTransformRepository *transformRepository, vtkXMLDataElement *serverElement, const std::string &configFilePath)
static vtkPlusCommandImageResponse * SafeDownCast(vtkObject *o)
ChannelContainerConstIterator GetOutputChannelsStart() const
virtual std::string GetPolyDataName()
virtual bool GetRespondWithCommandMessage()
virtual PlusStatus GetMostRecentTimestamp(double &ts)
virtual vtkImageData * GetImageData()
virtual void SetDataCollector(vtkPlusDataCollector *)
PlusStatus GetTrackedFrameList(double &aTimestampOfLastFrameAlreadyGot, vtkIGSIOTrackedFrameList *aTrackedFrameList, int aMaxNumberOfFramesToAdd)
const char * address
Definition: phidget22.h:2552
virtual std::string GetCommandName()
vtkStandardNewMacro(vtkPlusOpenIGTLinkServer)
std::vector< VideoStream > VideoStreams
Factory class of supported OpenIGTLink message types.
virtual unsigned int GetClientId()
static void * DataReceiverThread(vtkMultiThreader::ThreadInfo *data)
virtual PlusStatus GetStatus()
int GetClientHeaderVersion() const
static void * ConnectionReceiverThread(vtkMultiThreader::ThreadInfo *data)
igtl::ClientSocket::Pointer ClientSocket
IGTL client socket instance.
void GetImageMetaDataItems(igsioCommon::ImageMetaDataList &list)
void SetTDATARequested(bool val)
virtual vtkPolyData * GetPolyData()
virtual std::string GetDeviceName()
PlusStatus QueueMessageResponseForClient(int clientId, igtl::MessageBase::Pointer message)
static std::string GetPrefixFromCommandDeviceName(const std::string &deviceName)
static bool IsCommandDeviceName(const std::string &deviceName)
static std::string GetUidFromCommandDeviceName(const std::string &deviceName)
virtual PlusStatus GetOldestTimestamp(double &ts)
virtual std::string GetResultString()
static vtkPlusCommandRTSCommandResponse * SafeDownCast(vtkObject *o)
std::vector< vtkPlusDevice * >::iterator DeviceCollectionIterator
Definition: vtkPlusDevice.h:47
Contains an optional timestamped circular buffer containing the video images and a number of timestam...
static PlusStatus SendLatestFramesToClients(vtkPlusOpenIGTLinkServer &self, double &elapsedTimeSinceLastPacketSentSec)
virtual std::string GetImageName()
const char * message
Definition: phidget22.h:2457
static vtkPlusCommandPolydataResponse * SafeDownCast(vtkObject *o)
This class provides a network interface for data acquired by Plus as an OpenIGTLink server.
std::list< vtkSmartPointer< vtkPlusCommandResponse > > PlusCommandResponseList
virtual unsigned int GetNumberOfConnectedClients() const
This class provides client information for vtkPlusOpenIGTLinkServer.
int ToolCount() const
void SetTDATAResolution(int val)
for t
Definition: exploreFolders.m:9
int FieldCount() const
igtl::MessageBase::Pointer CreateIgtlMessageFromCommandResponse(vtkPlusCommandResponse *response)
virtual int OutputChannelCount() const
virtual void SetTransformRepository(vtkIGSIOTransformRepository *)
vtkSmartPointer< vtkIGSIOFrameConverter > FrameConverter
static PlusStatus PackPolyDataMessage(igtl::PolyDataMessage::Pointer polydataMessage, vtkSmartPointer< vtkPolyData > polyData, double timestamp)
static const std::string DEVICE_NAME_REPLY
static void * DataSenderThread(vtkMultiThreader::ThreadInfo *data)
virtual void PrintSelf(ostream &os, vtkIndent indent)