MITK-IGT
IGT Extension of MITK
Loading...
Searching...
No Matches
mitkMicroBirdTrackingDevice.cpp
Go to the documentation of this file.
1/*============================================================================
2
3The Medical Imaging Interaction Toolkit (MITK)
4
5Copyright (c) German Cancer Research Center (DKFZ)
6All rights reserved.
7
8Use of this source code is governed by a 3-clause BSD license that can be
9found in the LICENSE file.
10
11============================================================================*/
12
13#include "mitkMicrobirdTrackingDevice.h"
14
15#include <itksys/SystemTools.hxx>
16#include <itkMutexLockHolder.h>
17
18typedef itk::MutexLockHolder<itk::FastMutexLock> MutexLockHolder;
19
21m_ErrorMessage(""),
22m_ThreadID(0),
23m_pl(50), // 50 Hz for Europe
24m_metric(true),
25m_agcModeBoth(true),
26m_measurementRate(68.3), // 68.3 for mid-range transmitter, 40.5 for flat transmitter
27m_TransmitterConfig(nullptr),
28m_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 {
178 MutexLockHolder(*m_ToolsMutex);
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
283ITK_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
421mitk::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
447bool 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}
superclass for specific MIRCOBIRD tracking Devices
virtual unsigned int GetToolCount() const
returns a the number of attached sensors
virtual bool OpenConnection()
Builds up the connection (loads tools, initializes and enables them)
ToolType * GetMicroBirdTool(unsigned int toolNumber)
returns a tracking tool that contains positional information about one of the sensors
bool CompareError(int errorCode, int errorConstant)
virtual TrackingTool * GetTool(unsigned int toolNumber)
returns a tracking tool that contains positional information about one of the sensors
virtual void TrackTools()
tracks the position and orientation of all tools until StopTracking() is called.
bool SwitchTransmitter(bool switchOn)
Switches the transmitter on resp. off.
itk::MultiThreader::Pointer m_MultiThreader
virtual bool StopTracking()
here we use the superclass method.
virtual void InvalidateAll()
invalidates all tools (on stoptracking, closeconnection)
virtual bool StartTracking()
Start the tracking.
DOUBLE_POSITION_QUATERNION_TIME_Q_RECORD record
itk::FastMutexLock::Pointer m_ToolsMutex
DOUBLE_POSITION_QUATERNION_TIME_Q_RECORD * pRecord
One tracking data record (quaternion orientation format)
virtual bool CloseConnection()
Closes the connection.
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...
Interface for all Tracking Devices.
TrackingDeviceData m_Data
current device Data
virtual bool StopTracking()
stop retrieving tracking data from the device. stop retrieving tracking data from the device....
Interface for all Tracking Tools.
virtual void SetDataValid(bool isDataValid)
sets if the tracking data (position & orientation) is valid
virtual void SetTrackingError(float error)
sets the tracking error
virtual void SetOrientation(Quaternion orientation)
sets the orientation as a quaternion
virtual void SetPosition(Point3D position)
sets the position
itk::MutexLockHolder< itk::FastMutexLock > MutexLockHolder