Medical Imaging Interaction Toolkit  2018.4.99-389bf124
Medical Imaging Interaction Toolkit
mitkOphirPyro.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 "mitkOphirPyro.h"
14 
15 #include <chrono>
16 #include <ctime>
17 #include <thread>
18 #include <exception>
19 
21 m_CurrentWavelength(0),
22 m_DeviceHandle(0),
23 m_Connected(false),
24 m_Streaming(false),
25 m_SerialNumber(nullptr),
26 m_GetDataThread(),
27 m_ImagePyroDelay(0),
28 m_EnergyMultiplicator(60000)
29 {
30  m_PulseEnergy.clear();
31  m_PulseTime.clear();
32  m_PulseStatus.clear();
33  m_TimeStamps.clear();
34 }
35 
37 {
38  if (m_Connected)
39  {
40  this->CloseConnection();
41  if (m_GetDataThread.joinable())
42  {
43  m_GetDataThread.join();
44  MITK_INFO << "[OphirPyro Debug] joined data thread";
45  }
46  }
47  MITK_INFO << "[OphirPyro Debug] destroying that Pyro";
48  /* cleanup thread */
49 }
50 
52 {
53  if (ophirAPI.StartStream(m_DeviceHandle))
54  {
55  m_Streaming = true;
57  }
58  return m_Streaming;
59 }
60 
61 // this is just a little function to set the filenames below right
62 inline void replaceAll(std::string& str, const std::string& from, const std::string& to) {
63  if (from.empty())
64  return;
65  size_t start_pos = 0;
66  while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
67  str.replace(start_pos, from.length(), to);
68  start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx'
69  }
70 }
71 
73 {
74  // get the time and date, put them into a nice string and create a folder for the images
75  time_t time = std::time(nullptr);
76  time_t* timeptr = &time;
77  std::string currentDate = std::ctime(timeptr);
78  replaceAll(currentDate, ":", "-");
79  currentDate.pop_back();
80 
81  std::string pathTS = "c:\\ImageData\\" + currentDate + " pyro-ts" + ".csv";
82 
83  std::ofstream timestampFile;
84  timestampFile.open(pathTS);
85 
86  timestampFile << ",timestamp,PulseEnergy,PulseTime";
87 
88  int currentSize = m_TimeStamps.size();
89 
90  for (int index = 0; index < currentSize; ++index)
91  {
92  timestampFile << "\n" << index << "," << m_TimeStamps.at(index) << ","<< m_PulseEnergySaved.at(index) << "," << (long)m_PulseTimeSaved.at(index);
93  }
94  timestampFile.close();
95 }
96 
98 {
99  SaveCsvData();
100 }
101 
103 {
104  if (ophirAPI.StopStream(m_DeviceHandle))
105  m_Streaming = false;
106 
107  SaveCsvData();
108  MITK_INFO << "[OphirPyro Debug] m_Streaming = "<< m_Streaming;
109  std::this_thread::sleep_for(std::chrono::milliseconds(50));
110  if (m_GetDataThread.joinable())
111  {
112  m_GetDataThread.join();
113  }
114  return !m_Streaming;
115 }
116 
118 {
119  if (m_Streaming)
120  {
121  std::vector<double> newEnergy;
122  std::vector<double> newTimestamp;
123  std::vector<int> newStatus;
124  unsigned int noPackages = 0;
125  try
126  {
127  noPackages = ophirAPI.GetData(m_DeviceHandle, &newEnergy, &newTimestamp, &newStatus);
128  if (noPackages > 0)
129  {
130  m_PulseEnergy.insert(m_PulseEnergy.end(), newEnergy.begin(), newEnergy.end());
131  for (unsigned int i=0; i<noPackages; i++)
132  m_TimeStamps.push_back(std::chrono::high_resolution_clock::now().time_since_epoch().count());
133 
134  m_PulseTime.insert(m_PulseTime.end(), newTimestamp.begin(), newTimestamp.end());
135  m_PulseStatus.insert(m_PulseStatus.end(), newStatus.begin(), newStatus.end());
136 
137  m_PulseEnergySaved.insert(m_PulseEnergySaved.end(), newEnergy.begin(), newEnergy.end());
138  m_PulseTimeSaved.insert(m_PulseTimeSaved.end(), newTimestamp.begin(), newTimestamp.end());
139  m_PulseStatusSaved.insert(m_PulseStatusSaved.end(), newStatus.begin(), newStatus.end());
140  }
141  }
142  catch (std::exception& ex)
143  {
144  MITK_INFO << "this is weird: " << ex.what();
145  }
146  return noPackages;
147  }
148  return 0;
149 }
150 
152 {
153  while(m_Connected && m_Streaming)
154  {
155  this->GetDataFromSensor();
156  std::this_thread::sleep_for(std::chrono::milliseconds(50));
157  }
158  return;
159 }
160 
162 {
163  if (m_Connected && !m_PulseEnergy.empty())
164  {
165  MITK_INFO << m_PulseEnergy.size();
166  return m_PulseEnergy.back();
167  }
168  return 0;
169 }
170 
171 double mitk::OphirPyro::GetClosestEnergyInmJ(long long ImageTimeStamp, double interval)
172 {
173  if (m_PulseTime.size() == 0)
174  return 0;
175 
176  long long searchTime = (ImageTimeStamp/1000000) - m_ImagePyroDelay; // conversion from ns to ms
177 
178  //MITK_INFO << "searchTime = " << searchTime;
179  int foundIndex = -1;
180  long long shortestDifference = 250*interval;
181 
182  // search the list for a fitting energy value time
183  for (int index = 0; index < m_PulseTime.size();++index)
184  {
185  long long newDifference = abs(((int)m_PulseTime[index]) - searchTime);
186  //MITK_INFO << "newDifference[" << index << "] = " << newDifference;
187  if (newDifference < shortestDifference)
188  {
189  shortestDifference = newDifference;
190  foundIndex = index;
191  //MITK_INFO << "foundIndex = " << foundIndex;
192  }
193  }
194 
195  if (abs(shortestDifference) < interval)
196  {
197  // delete all elements before the one found
198  m_PulseEnergy.erase(m_PulseEnergy.begin(), m_PulseEnergy.begin() + foundIndex);
199  m_PulseTime.erase(m_PulseTime.begin(), m_PulseTime.begin() + foundIndex);
200  m_PulseStatus.erase(m_PulseStatus.begin(), m_PulseStatus.begin() + foundIndex);
201 
202  // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy
204  }
205 
206  //MITK_INFO << "No matching energy value for image found in interval of " << interval << "ms. sd: " << shortestDifference;
207  return -1;
208 }
209 
210 double mitk::OphirPyro::GetNextEnergyInmJ(long long ImageTimeStamp, double interval)
211 {
212  if (m_Connected && !(m_PulseTime.size() > 0))
213  return 0;
214 
215  long long searchTime = (ImageTimeStamp / 1000000) - m_ImagePyroDelay; // conversion from ns to ms
216 
217  if (abs(searchTime - m_PulseTime.front()) < interval)
218  {
219  return (GetNextPulseEnergy()*m_EnergyMultiplicator); // multipy with m_EnergyMultiplicator, because the Pyro gives just a fraction of the actual Laser Energy
220  }
221 
222  MITK_INFO << "Image aquisition and energy measurement ran out of sync";
223  return -1;
224 }
225 
226 void mitk::OphirPyro::SetSyncDelay(long long FirstImageTimeStamp)
227 {
228  while (!m_PulseTime.size())
229  {
230  std::this_thread::sleep_for(std::chrono::milliseconds(1));
231  }
232  m_ImagePyroDelay = (FirstImageTimeStamp / 1000000) - m_PulseTime.at(0);
233 
234  MITK_INFO << "m_ImagePyroDelay = " << m_ImagePyroDelay;
235  return;
236 }
237 
239 {
240  return (m_ImagePyroDelay != 0);
241 }
242 
244 {
245  if (m_Connected && m_PulseEnergy.size()>=1)
246  {
247  double out = m_PulseEnergy.front();
248  m_PulseEnergy.erase(m_PulseEnergy.begin());
249  m_PulseTime.erase(m_PulseTime.begin());
250  m_PulseStatus.erase(m_PulseStatus.begin());
251  return out;
252  }
253  return 0;
254 }
255 
256 double mitk::OphirPyro::LookupCurrentPulseEnergy(double* timestamp, int* status)
257 {
258  if (m_Connected)
259  {
260  *timestamp = m_PulseTime.back();
261  *status = m_PulseStatus.back();
262  return m_PulseEnergy.back();
263  }
264  return 0;
265 }
266 
267 double mitk::OphirPyro::GetNextPulseEnergy(double* timestamp, int* status)
268 {
269  if (m_Connected)
270  {
271  double out = m_PulseEnergy.front();
272  *timestamp = m_PulseTime.front();
273  *status = m_PulseStatus.front();
274  m_PulseEnergy.erase(m_PulseEnergy.begin());
275  m_PulseTime.erase(m_PulseTime.begin());
276  m_PulseStatus.erase(m_PulseStatus.begin());
277  return out;
278  }
279  return 0;
280 }
281 
283 {
284  if (!m_Connected)
285  {
286  char* m_SerialNumber;
287  try {
288  MITK_INFO << "Scanning for Ophir connection";
289  m_SerialNumber = ophirAPI.ScanUSB();
290  }
291  catch (...)
292  {
293  MITK_INFO << "Scanning failed, trying again in 2 seconds...";
294  std::this_thread::sleep_for(std::chrono::seconds(2));
295  MITK_INFO << "Scanning for Ophir connection";
296  m_SerialNumber = ophirAPI.ScanUSB();
297  }
298 
299  if (m_SerialNumber != 0)
300  {
301  try {
302  MITK_INFO << "Opening Ophir connection";
303  m_DeviceHandle = ophirAPI.OpenDevice(m_SerialNumber);
304  }
305  catch (...)
306  {
307  MITK_INFO << "Ophir connection failed, trying again in 2 seconds...";
308  std::this_thread::sleep_for(std::chrono::seconds(2));
309  MITK_INFO << "Opening Ophir connection";
310  m_DeviceHandle = ophirAPI.OpenDevice(m_SerialNumber);
311  }
312 
313  if (m_DeviceHandle != 0)
314  {
315  m_Connected = true;
316  return true;
317  }
318  }
319  }
320  return false;
321 }
322 
324 {
325  if (m_Connected)
326  {
327  bool closed = ophirAPI.CloseDevice(m_DeviceHandle);
328  if (closed) m_DeviceHandle = 0;
329  m_Connected = !closed;
330  return closed;
331  }
332  return false;
333 }
virtual bool IsSyncDelaySet()
#define MITK_INFO
Definition: mitkLogMacros.h:18
std::vector< double > m_PulseTime
Definition: mitkOphirPyro.h:72
virtual bool CloseConnection()
virtual double LookupCurrentPulseEnergy()
virtual void SetSyncDelay(long long FirstImageTimeStamp)
std::vector< double > m_PulseEnergySaved
Definition: mitkOphirPyro.h:76
char * m_SerialNumber
Definition: mitkOphirPyro.h:67
virtual double GetNextPulseEnergy()
float m_EnergyMultiplicator
Definition: mitkOphirPyro.h:84
std::thread m_GetDataThread
Definition: mitkOphirPyro.h:86
long long m_ImagePyroDelay
Definition: mitkOphirPyro.h:83
std::vector< int > m_PulseStatus
Definition: mitkOphirPyro.h:73
std::vector< double > m_PulseTimeSaved
Definition: mitkOphirPyro.h:77
virtual bool StopDataAcquisition()
virtual double GetNextEnergyInmJ(long long ImageTimeStamp, double interval=20)
std::vector< int > m_PulseStatusSaved
Definition: mitkOphirPyro.h:78
virtual bool StartDataAcquisition()
void GetDataFromSensorThread()
virtual double GetClosestEnergyInmJ(long long ImageTimeStamp, double interval=20)
OphirPyroWrapper ophirAPI
Definition: mitkOphirPyro.h:66
std::vector< long long > m_TimeStamps
Definition: mitkOphirPyro.h:74
unsigned int GetDataFromSensor()
std::vector< double > m_PulseEnergy
Definition: mitkOphirPyro.h:71
virtual bool OpenConnection()
void replaceAll(std::string &str, const std::string &from, const std::string &to)
virtual ~OphirPyro()