Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkMicroBirdTrackingDevice.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 (DKFZ)
6 All rights reserved.
7 
8 Use of this source code is governed by a 3-clause BSD license that can be
9 found in the LICENSE file.
10 
11 ============================================================================*/
12 
13 #include "mitkMicrobirdTrackingDevice.h"
14 
15 #include <itksys/SystemTools.hxx>
16 #include <itkMutexLockHolder.h>
17 
19 
21 m_ErrorMessage(""),
22 m_ThreadID(0),
23 m_pl(50), // 50 Hz for Europe
24 m_metric(true),
25 m_agcModeBoth(true),
26 m_measurementRate(68.3), // 68.3 for mid-range transmitter, 40.5 for flat transmitter
27 m_TransmitterConfig(nullptr),
28 m_SensorConfig(nullptr)
29 {
30  // Flat transmitter needs measurement rate: 40.5
31  // Mid-range transmitter needs measurement rate: 68.3;
32 
33  // Set the tracker type
34  this->m_Data = mitk::DeviceDataMicroBird;
35 
36  // Clear tools vector
37  m_Tools.clear();
38 
39  // Create tools vector mutex
40  m_ToolsMutex = itk::FastMutexLock::New();
41 
42  // Prepare multi-threading
43  m_MultiThreader = itk::MultiThreader::New();
44 
45  // Pointer to record member variable
46  pRecord = &record;
47 }
48 
49 
51 {
52  if (m_MultiThreader)
53  m_MultiThreader->TerminateThread(m_ThreadID);
54  m_MultiThreader = nullptr;
55  if (m_ToolsMutex)
56  m_ToolsMutex->Unlock();
57  m_ToolsMutex = nullptr;
58 
59  this->StopTracking();
60  this->CloseConnection();
61 
62  if (m_TransmitterConfig != nullptr)
63  delete [] m_TransmitterConfig;
64  if (m_SensorConfig != nullptr)
65  delete [] m_SensorConfig;
66 
67  //\TODO: Do we need to clean up the pointers to PCIBird data like DOUBLE_POSITION_QUATERNION_TIME_Q_RECORD?
68 }
69 
70 
72 {
73  /* Check whether in setup mode */
74  if (this->GetState() != Setup)
75  {
76  this->SetErrorMessage("Can only try to open the connection if in setup mode");
77  return false;
78  }
79 
80  int errorCode; // Holds error code
81 
82  /* Initialize the PCIBIRD driver and DLL */
83  errorCode = InitializeBIRDSystem(); // this function can take a few seconds
84  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
85  {
86  HandleError(errorCode);
87  return false;
88  }
90  // Serial numbers could be compared to known ones for some simple
91  // parameters sanity check (measurement frequency etc.)
92 
93  /* Get system configuration */
94  errorCode = GetBIRDSystemConfiguration(&m_SystemConfig);
95  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
96  {
97  HandleError(errorCode);
98  return false;
99  }
100 
101  /* use metric measurements in mm */
102  errorCode = SetSystemParameter(METRIC, &m_metric, sizeof(m_metric));
103  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
104  {
105  HandleError(errorCode);
106  return false;
107  }
108 
109  /* Set the measurement rate to m_measurementRate */
110  if ((m_measurementRate > 30) && (m_measurementRate < 80))
111  {
112  errorCode = SetSystemParameter(MEASUREMENT_RATE, &m_measurementRate, sizeof(m_measurementRate));
113  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
114  {
115  HandleError(errorCode);
116  return false;
117  }
118  }
119 
120  /* Set power line frequency */
121  if ((m_pl >= 50) && (m_pl <= 60))
122  {
123  errorCode = SetSystemParameter(POWER_LINE_FREQUENCY, &m_pl, sizeof(m_pl));
124  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
125  {
126  HandleError(errorCode);
127  return false;
128  }
129  }
130 
131  /* Set AGC mode */
132  m_agc = m_agcModeBoth ? TRANSMITTER_AND_SENSOR_AGC : SENSOR_AGC_ONLY;
133  errorCode = SetSystemParameter(AGC_MODE, &m_agc, sizeof(m_agc));
134  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
135  {
136  HandleError(errorCode);
137  return false;
138  }
139 
140  /* Get system configuration */
141  errorCode = GetBIRDSystemConfiguration(&m_SystemConfig);
142  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
143  {
144  HandleError(errorCode);
145  return false;
146  }
147 
148  /* Get sensor information */
149  m_SensorConfig = new SENSOR_CONFIGURATION[m_SystemConfig.numberSensors];
150  for (int i = 0; i < m_SystemConfig.numberSensors; i++)
151  {
152  errorCode = GetSensorConfiguration(i, &(m_SensorConfig[i]));
153  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
154  {
155  HandleError(errorCode);
156  }
157 
158  /* Initialize the quality parameter structure */
159  QUALITY_PARAMETERS qualityParameters; // = { 164, 0, 32, 3072 };
160  GetSensorParameter(i, QUALITY, &qualityParameters, sizeof(qualityParameters));
161 
162  /* Set data format to matrix format */
163  //DATA_FORMAT_TYPE tempBuffer = DOUBLE_POSITION_MATRIX_TIME_Q;
164  /* Set data format to quaternion format */
165  DATA_FORMAT_TYPE tempBuffer = DOUBLE_POSITION_QUATERNION_TIME_Q;
166 
167  /* Set data format for sensor */
168  DATA_FORMAT_TYPE *pTempBuffer = &tempBuffer;
169  errorCode = SetSensorParameter(i, DATA_FORMAT, pTempBuffer, sizeof(tempBuffer));
170  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
171  {
172  HandleError(errorCode);
173  }
174  }
175 
176  /* Initialize tools vector */
177  {
179  for (int i = 0; i < m_SystemConfig.numberSensors; i++)
180  {
181  if (m_SensorConfig[i].attached)
182  m_Tools.push_back(ToolType::New());
183 
184  }
185  }
186 
187  /* Get transmitter configuration */
188  m_TransmitterConfig = new TRANSMITTER_CONFIGURATION[m_SystemConfig.numberTransmitters];
189  for (int i = 0; i < m_SystemConfig.numberTransmitters; i++)
190  {
191  errorCode = GetTransmitterConfiguration(i, &(m_TransmitterConfig[i]));
192  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
193  {
194  HandleError(errorCode);
195  }
196  }
197 
198  /* Switch off transmitter */
199  SwitchTransmitter(true);
200  SwitchTransmitter(false);
201 
202  // @todo : set up error scaling?
203 
204  /* finish - now all tools should be added, initialized and enabled, so that tracking can be started */
205  this->SetState(Ready);
206  this->SetErrorMessage("");
207  return true; // Return success
208 }
209 
210 
212 {
213  if (switchOn)
214  {
215  /* Search for the first attached transmitter and turn it on */
216  for (short id = 0; id < m_SystemConfig.numberTransmitters; id++)
217  {
218  if (m_TransmitterConfig[id].attached)
219  {
220  // Transmitter selection is a system function.
221  // Using the SELECT_TRANSMITTER parameter we send the id of the
222  // transmitter that we want to run with the SetSystemParameter() call
223  int errorCode = SetSystemParameter(SELECT_TRANSMITTER, &id, sizeof(id));
224  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
225  {
226  HandleError(errorCode);
227  return false;
228  }
229  else
230  return true; //break; // \TODO: Stop after the first attached transmitter was turned off?
231  }
232  }
233  }
234  else
235  {
236  /* Transmitter selection is a system function, Note: a selector of -1 switches off the current transmitter */
237  short TRANSMITTER_OFF = -1;
238  int errorCode = SetSystemParameter(SELECT_TRANSMITTER, &TRANSMITTER_OFF, sizeof(TRANSMITTER_OFF));
239  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
240  {
241  HandleError(errorCode);
242  return false;
243  }
244  else
245  return true;
246  }
247  // Return success
248  return true;
249 }
250 
251 
253 {
254  SwitchTransmitter(false); // Switch off the transmitter
255 
256  int errorCode = CloseBIRDSystem(); // Close connection. This function can take a few seconds
257 
258  // Error checking
259  if (!CompareError(errorCode, BIRD_ERROR_SUCCESS))
260  HandleError(errorCode);
261 
262  // Delete configuration
263  if (m_TransmitterConfig != nullptr)
264  {
265  delete [] m_TransmitterConfig;
266  m_TransmitterConfig = nullptr;
267  }
268  if (m_SensorConfig != nullptr)
269  {
270  delete [] m_SensorConfig;
271  m_SensorConfig = nullptr;
272  }
273  // Change mode and release mutex
274  this->SetState(Setup);
275 
276  // Clear error message
277  this->SetErrorMessage("");
278 
279  return true;
280 }
281 
282 
283 ITK_THREAD_RETURN_TYPE mitk::MicroBirdTrackingDevice::ThreadStartTracking(void* pInfoStruct)
284 {
285  /* extract this pointer from Thread Info structure */
286  struct itk::MultiThreader::ThreadInfoStruct * pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct;
287  if ((pInfo == nullptr) || (pInfo->UserData == nullptr))
288  return ITK_THREAD_RETURN_VALUE;
289 
290  MicroBirdTrackingDevice *trackingDevice = (MicroBirdTrackingDevice*)pInfo->UserData;
291  if (trackingDevice != nullptr)
292  trackingDevice->TrackTools(); // call TrackTools() from the original object
293 
294  return ITK_THREAD_RETURN_VALUE;
295 }
296 
297 
299 {
300  TrackingDevice::StopTracking(); // Call superclass method
301 
302  SwitchTransmitter(false); // Switch off transmitter
303  InvalidateAll(); // Invalidate all tools
304  return true; // \todo : think about return value
305 }
306 
307 
309 {
310  if (this->GetState() != Ready)
311  return false;
312 
313  this->SetState(Tracking);
314 
315  /* Switch on transmitter */
316  SwitchTransmitter(true);
317 
318  /* Update the local copy of m_StopTracking */
319  this->m_StopTrackingMutex->Lock();
320  this->m_StopTracking = false;
321  this->m_StopTrackingMutex->Unlock();
322 
323  m_TrackingFinishedMutex->Unlock(); // transfer the execution rights to tracking thread
324  m_ThreadID = m_MultiThreader->SpawnThread(this->ThreadStartTracking, this); // start a new thread that executes the TrackTools() method
325  mitk::TimeStamp::GetInstance()->Start(this);
326  return true;
327 }
328 
329 
331 {
332  if (this->GetState() != Tracking)
333  return;
334 
335  /* Frequency configuration */
336  double updateRate = 1000.0 / m_SystemConfig.measurementRate;
337  double measurementDuration = 0.0;
338 
339 
340  // lock the TrackingFinishedMutex to signal that the execution rights
341  // are now transfered to the tracking thread
342  MutexLockHolder trackingFinishedLockHolder(*m_TrackingFinishedMutex); // keep lock until end of scope
343 
344  // Because m_StopTracking is used by two threads, access has to be guarded
345  // by a mutex. To minimize thread locking, a local copy is used here
346  bool localStopTracking;
347 
348  /* update the local copy of m_StopTracking */
349  this->m_StopTrackingMutex->Lock();
350  localStopTracking = this->m_StopTracking;
351  this->m_StopTrackingMutex->Unlock();
352 
353  /* Tracking loop */
354  while ((this->GetState() == Tracking) && (localStopTracking == false))
355  {
356  int errorCode;
357  unsigned int nOfAttachedSensors = 0;
358  double timeStamp = 0.0;
359  int toolNumber = 0; // Numbers for attached sensors only
360 
361  for (int sensorID = 0; sensorID < m_SystemConfig.numberSensors; sensorID++) // for each sensor grep data
362  {
363  if (!m_SensorConfig[sensorID].attached)
364  continue;
365 
366  // sensor attached so get record
367  errorCode = GetAsynchronousRecord(sensorID, pRecord, sizeof(record));
368  if (CompareError(errorCode, BIRD_ERROR_SUCCESS))
369  { // On SUCCESS, parse sensor information
370  nOfAttachedSensors++;
371  timeStamp += record.time; // Get timestamp from record
372  ToolType* tool = GetMicroBirdTool(toolNumber);
373  if (tool != nullptr)
374  {
375  tool->SetTrackingError(record.quality); // Set tracking error (quality) from record
376  mitk::Point3D position;
377  position[0] = record.x;
378  position[1] = record.y;
379  position[2] = record.z;
380  tool->SetPosition(position); // Set position
381  mitk::Quaternion orientation(record.q[1], record.q[2], record.q[3],record.q[0]);
382  tool->SetOrientation(orientation); // Set orientation as quaternion \todo : verify quaternion order q(r,x,y,z)
383  tool->SetDataValid(true); // Set data state to valid
384  }
385  toolNumber++; // Increment tool number
386  }
387  else
388  { // ERROR while reading sensor information
389  HandleError(errorCode);
390  }
391  }
392 
394  // Average timestamp: timeStamp/nOfAttachedSensors
395 
396  // Compute sleep time
397  double sleepTime = updateRate - measurementDuration;
398  // Sleep
399  if (sleepTime > 0.0 && sleepTime < 500.0)
400  {
401  // Note: we only have to approximately sleep one measurement cycle,
402  // since the tracker keeps track of the measurement rate itself
403  itksys::SystemTools::Delay(sleepTime)
404  //Sleep(static_cast<DWORD>(sleepTime));
405  }
406 
407  // Update the local copy of m_StopTracking
408  this->m_StopTrackingMutex->Lock();
409  localStopTracking = m_StopTracking;
410  this->m_StopTrackingMutex->Unlock();
411  }
412 
413  // @bug (#1813) : maybe we need to check for localStopTracking=true here?
414  // m_StopTracking should only ever be updated by StopTracking(), so
415  // maybe we should not unlock a mutex that nobody is waiting for?
416 
417  return; // returning from this function (and ThreadStartTracking()) this will end the thread
418 }
419 
420 
421 mitk::ToolType* mitk::MicroBirdTrackingDevice::GetTool(unsigned int toolNumber)
422 {
423  return static_cast<ToolType*>(GetMicroBirdTool(toolNumber));
424 }
425 
426 
428 {
429  ToolType* t = nullptr;
430 
431  MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex
432  if (toolNumber < m_Tools.size())
433  {
434  t = m_Tools.at(toolNumber);
435  }
436  return t;
437 }
438 
439 
441 {
442  MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex
443  return m_Tools.size();
444 }
445 
446 
447 bool mitk::MicroBirdTrackingDevice::CompareError(int errorCode, int errorConstant)
448 {
449  return ((errorCode & 0xffff) == errorConstant);
450 }
451 
452 
454 {
455  char buffer[1024];
456  char* pBuffer = &buffer[0];
457 
458  while(!CompareError(errorCode, BIRD_ERROR_SUCCESS))
459  {
460  // Print error number on screen
461  //cout << "MicroBIRD Error Code: " << errorCode << endl;
462  // Print error message on screen
463  errorCode = GetErrorText(errorCode, pBuffer, sizeof(buffer), SIMPLE_MESSAGE);
465  this->SetErrorMessage(buffer);
466  }
467 }
468 
469 
471 {
472  MutexLockHolder toolsMutexLockHolder(*m_ToolsMutex); // lock and unlock the mutex
473  for (ToolContainerType::iterator iterator = m_Tools.begin(); iterator != m_Tools.end(); ++iterator)
474  (*iterator)->SetDataValid(false);
475 }
virtual void SetErrorMessage(const char *_arg)
Interface for all Tracking Tools.
itk::FastMutexLock::Pointer m_TrackingFinishedMutex
mutex to manage control flow of StopTracking()
virtual bool CloseConnection()
Closes the connection.
superclass for specific MIRCOBIRD tracking Devices
virtual void InvalidateAll()
invalidates all tools (on stoptracking, closeconnection)
bool CompareError(int errorCode, int errorConstant)
itk::FastMutexLock::Pointer m_ToolsMutex
virtual bool OpenConnection()
Builds up the connection (loads tools, initializes and enables them)
TrackingDeviceState GetState() const
return current object state (Setup, Ready or Tracking)
virtual void SetOrientation(Quaternion orientation)
sets the orientation as a quaternion
bool m_agcModeBoth
AGC (automatic gain control) mode flag.
itk::MultiThreader::Pointer m_MultiThreader
itk::MutexLockHolder< itk::FastMutexLock > MutexLockHolder
virtual void SetPosition(Point3D position)
sets the position
virtual bool StartTracking()
Start the tracking.
static ITK_THREAD_RETURN_TYPE ThreadStartTracking(void *data)
Helper function, because the itk::MultiThreader can only start a new thread with a static member func...
virtual TrackingTool * GetTool(unsigned int toolNumber)
returns a tracking tool that contains positional information about one of the sensors ...
virtual bool StopTracking()
stop retrieving tracking data from the device. stop retrieving tracking data from the device...
DOUBLE_POSITION_QUATERNION_TIME_Q_RECORD * pRecord
One tracking data record (quaternion orientation format)
bool SwitchTransmitter(bool switchOn)
Switches the transmitter on resp. off.
BOOL m_metric
Specifies whether metric measurement is used.
SENSOR_CONFIGURATION * m_SensorConfig
The sensor configuration - used to get and set the sensor properties.
bool m_StopTracking
signal stop to tracking thread
Interface for all Tracking Devices.
SYSTEM_CONFIGURATION m_SystemConfig
The system configuration - used to specify its use.
vnl_quaternion< ScalarType > Quaternion
double m_measurementRate
Specifies the measurement rate - default set to maximum.
double m_pl
Specifies the power line frequency (Europe 50Hz, USA 60Hz)
virtual bool StopTracking()
here we use the superclass method.
static Pointer New()
TrackingDeviceData m_Data
current device Data
itk::FastMutexLock::Pointer m_StopTrackingMutex
mutex to control access to m_StopTracking
virtual void TrackTools()
tracks the position and orientation of all tools until StopTracking() is called.
virtual void SetDataValid(bool isDataValid)
sets if the tracking data (position & orientation) is valid
virtual unsigned int GetToolCount() const
returns a the number of attached sensors
TRANSMITTER_CONFIGURATION * m_TransmitterConfig
The transmitter configuration - used to get and set the transmitter properties.
void SetState(TrackingDeviceState state)
change object state
DOUBLE_POSITION_QUATERNION_TIME_Q_RECORD record
virtual void SetTrackingError(float error)
sets the tracking error
ToolType * GetMicroBirdTool(unsigned int toolNumber)
returns a tracking tool that contains positional information about one of the sensors ...