PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
PlusServer.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 
14 #include "PlusConfigure.h"
15 #include "igsioCommon.h"
16 #include "vtkNew.h"
17 #include "vtkPlusDataCollector.h"
19 #include "vtkPlusBuffer.h"
20 #include "vtkPlusChannel.h"
21 #include "vtkPlusDataSource.h"
23 #include "vtkSmartPointer.h"
24 #include "vtkIGSIOTransformRepository.h"
25 #include "vtksys/CommandLineArguments.hxx"
26 
27 // For catching Ctrl-C
28 #include <csignal>
29 #include <cstdlib>
30 #include <cstdio>
31 
32 // Forward declare signal handler
33 void SignalInterruptHandler(int s);
34 static bool stopRequested = false;
35 #ifdef _WIN32
36 void CheckConsoleWindowCloseRequested(HWND consoleHwnd);
37 #endif
38 
39 //-----------------------------------------------------------------------------
40 int main(int argc, char** argv)
41 {
42  // Check command line arguments.
43  bool printHelp(false);
44  std::string inputConfigFileName;
45  std::string testingConfigFileName;
46  int verboseLevel = vtkPlusLogger::LOG_LEVEL_UNDEFINED;
47  double runTimeSec = 0.0;
48 
49  const int numOfTestClientsToConnect = 5; // only if testing is enabled S
50 
51  vtksys::CommandLineArguments args;
52  args.Initialize(argc, argv);
53 
54  args.AddArgument("--help", vtksys::CommandLineArguments::NO_ARGUMENT, &printHelp, "Print this help.");
55  args.AddArgument("--config-file", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &inputConfigFileName, "Name of the input configuration file.");
56  args.AddArgument("--running-time", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &runTimeSec, "Server running time period in seconds. If the parameter is not defined or 0 then the server runs infinitely.");
57  args.AddArgument("--verbose", vtksys::CommandLineArguments::EQUAL_ARGUMENT, &verboseLevel, "Verbose level (1=error only, 2=warning, 3=info, 4=debug, 5=trace)");
58 
59  if (!args.Parse())
60  {
61  std::cerr << "Problem parsing arguments." << std::endl;
62  std::cout << "Help: " << args.GetHelp() << std::endl;
63  exit(EXIT_FAILURE);
64  }
65 
66  if (printHelp)
67  {
68  std::cout << args.GetHelp() << std::endl;
69  exit(EXIT_SUCCESS);
70  }
71 
72  vtkPlusLogger::Instance()->SetLogLevel(verboseLevel);
73 
74  if (inputConfigFileName.empty())
75  {
76  LOG_ERROR("--config-file argument is required!");
77  std::cout << "Help: " << args.GetHelp() << std::endl;
78  exit(EXIT_FAILURE);
79  }
80 
81  LOG_INFO("Logging at level " << vtkPlusLogger::Instance()->GetLogLevel() << " (" << vtkPlusLogger::Instance()->GetLogLevelString() << ") to file: " << vtkPlusLogger::Instance()->GetLogFileName());
82 
83  // Read main configuration file
84  vtkNew<vtkPlusDataCollector> dataCollector;
85  if (dataCollector->ReadConfiguration(inputConfigFileName) != PLUS_SUCCESS)
86  {
87  LOG_ERROR("Datacollector failed to read configuration");
88  exit(EXIT_FAILURE);
89  }
90 
91  // Recover config root element
92  LOG_INFO("Server status: Reading configuration.");
93  vtkXMLDataElement* configRootElement = vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationData();
94 
95  // Create transform repository instance
96  vtkNew<vtkIGSIOTransformRepository> transformRepository;
97  if (transformRepository->ReadConfiguration(configRootElement) != PLUS_SUCCESS)
98  {
99  LOG_ERROR("Transform repository failed to read configuration");
100  exit(EXIT_FAILURE);
101  }
102 
103  LOG_INFO("Server status: Connecting to devices.");
104  if (dataCollector->Connect() != PLUS_SUCCESS)
105  {
106  LOG_ERROR("Datacollector failed to connect to devices");
107  exit(EXIT_FAILURE);
108  }
109 
110  if (dataCollector->Start() != PLUS_SUCCESS)
111  {
112  LOG_ERROR("Datacollector failed to start");
113  exit(EXIT_FAILURE);
114  }
115 
116  LOG_INFO("Server status: Starting servers.");
117  std::vector<vtkPlusOpenIGTLinkServer*> serverList;
118  int serverCount(0);
119  for (int i = 0; i < configRootElement->GetNumberOfNestedElements(); ++i)
120  {
121  vtkXMLDataElement* serverElement = configRootElement->GetNestedElement(i);
122  if (STRCASECMP(serverElement->GetName(), "PlusOpenIGTLinkServer") != 0)
123  {
124  continue;
125  }
126 
127  serverCount++;
128 
129  // This is a PlusServer tag, let's create it
130  vtkSmartPointer<vtkPlusOpenIGTLinkServer> server = vtkSmartPointer<vtkPlusOpenIGTLinkServer>::New();
131  LOG_DEBUG("Initializing Plus OpenIGTLink server... ");
132  if (server->Start(dataCollector.GetPointer(), transformRepository.GetPointer(), serverElement, vtkPlusConfig::GetInstance()->GetDeviceSetConfigurationFileName()) != PLUS_SUCCESS)
133  {
134  LOG_ERROR("Failed to start OpenIGTLink server");
135  exit(EXIT_FAILURE);
136  }
137  serverList.push_back(server);
138  }
139  if (serverCount == 0)
140  {
141  LOG_ERROR("No vtkPlusOpenIGTLinkServer tags were found in the configuration file. Please add at least one.");
142  exit(EXIT_FAILURE);
143  }
144 
145  double startTime = vtkIGSIOAccurateTimer::GetSystemTime();
146 
147  LOG_INFO("Server status: Server(s) are running.");
148  LOG_INFO("Press Ctrl-C to quit.");
149 
150  // Set up signal catching
151  signal(SIGINT, SignalInterruptHandler);
152 #ifdef _WIN32
153  HWND consoleHwnd = GetConsoleWindow();
154 #endif
155 
156  bool neverStop = (runTimeSec == 0.0);
157 
158  // Run server until requested
159  const double commandQueuePollIntervalSec = 0.010;
160  while ((neverStop || (vtkIGSIOAccurateTimer::GetSystemTime() < startTime + runTimeSec)) && !stopRequested)
161  {
162  for (std::vector<vtkPlusOpenIGTLinkServer*>::iterator it = serverList.begin(); it != serverList.end(); ++it)
163  {
164  (*it)->ProcessPendingCommands();
165  }
166 #if _WIN32
167  // Check if received message that requested process termination (non-Windows systems always use signals).
168  // Need to do it before processing messages.
169  CheckConsoleWindowCloseRequested(consoleHwnd);
170 #endif
171  // Need to process messages while waiting because some devices (such as the vtkPlusWin32VideoSource2) require event processing
172  vtkIGSIOAccurateTimer::DelayWithEventProcessing(commandQueuePollIntervalSec);
173  }
174 
175  for (std::vector<vtkPlusOpenIGTLinkServer*>::iterator it = serverList.begin(); it != serverList.end(); ++it)
176  {
177  (*it)->Stop();
178  }
179 
180  LOG_INFO("Shutdown successful.");
181 
182  return EXIT_SUCCESS;
183 }
184 
185 // -------------------------------------------------
187 {
188  LOG_INFO("Stop requested...");
189  stopRequested = true;
190 }
191 
192 #ifdef _WIN32
193 //-----------------------------------------------------------------------------
194 // On Windows Qt cannot send SIGINT signal to indicate that the process should exit (ctrl-c),
195 // it can only send WM_CLOSE message to all of its windows. Therefore, we check for WM_CLOSE
196 // messages and stop if we receive one.
197 void CheckConsoleWindowCloseRequested(HWND consoleHwnd)
198 {
199  MSG msg;
200  if (PeekMessage(&msg, 0, WM_CLOSE, WM_CLOSE, PM_NOREMOVE))
201  {
202  // Qt usually sends WM_CLOSE with a proper (non-NULL) HWND when calling QProcess::terminate()
203  // the launched application. However, on WindowsXP embedded we receive a NULL as HWND, so
204  // accept that, too.
205  if (msg.hwnd == NULL || msg.hwnd == consoleHwnd)
206  {
207  stopRequested = true;
208  }
209  }
210 }
211 #endif
std::string GetDeviceSetConfigurationFileName()
for i
void SignalInterruptHandler(int s)
Definition: PlusServer.cxx:186
static vtkPlusConfig * GetInstance()
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
static vtkIGSIOLogger * Instance()
int main(int argc, char **argv)
Definition: PlusServer.cxx:40
virtual vtkXMLDataElement * GetDeviceSetConfigurationData()
static bool stopRequested
Definition: PlusServer.cxx:34
vtkNew< vtkPlusOpenIGTLinkServer > server