PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusThorLabsVideoSource.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 #include "PlusConfigure.h"
8 #include "vtkObjectFactory.h"
9 #include "vtkPlusChannel.h"
10 #include "vtkPlusDataSource.h"
11 #include "vtkUnsignedCharArray.h"
13 
14 //#include "c:\\Users\\lasso\\devel\\PLTools\\ThorLabs\\VISA\\Win64\\TLCCS\\TLCCS.c"
15 
16 //#include <ansi_c.h>
17 //#include <stdio.h> // stdio for file operations
18 //#include <time.h> // time stamps
19 
20 // ThorLabs SDK headers
21 #include <visa.h>
22 #include "TLCCS.h"
23 
24 class vtkPlusThorLabsVideoSourceInternal
25 {
26 public:
27  //----------------------------------------------------------------------------
28  vtkPlusThorLabsVideoSourceInternal()
29  : InstrumentHandle(VI_NULL)
30  {
31  }
32  //----------------------------------------------------------------------------
33  virtual ~vtkPlusThorLabsVideoSourceInternal()
34  {
35  }
36 
37  //----------------------------------------------------------------------------
38  std::string GetThorLabsErrorString(ViStatus err)
39  {
40  ViChar ebuf[TLCCS_ERR_DESCR_BUFFER_SIZE];
41  tlccs_error_message (this->InstrumentHandle, err, ebuf);
42  return ebuf;
43  }
44 
45  ViSession InstrumentHandle;
46  ViReal64 WavelengthIntensityDataBuffer[2*TLCCS_NUM_PIXELS]; // TLCCS_NUM_PIXELS wavelength values followed by TLCCS_NUM_PIXELS intensity values
47 };
48 
50 
51 //----------------------------------------------------------------------------
53 : Internal(new vtkPlusThorLabsVideoSourceInternal)
54 , InstrumentName(NULL)
55 , IntegrationTimeSec(0.050)
56 , FrameIndex(0)
57 {
59  this->StartThreadForInternalUpdates = true;
60 }
61 
62 //----------------------------------------------------------------------------
64 {
65  delete this->Internal;
66  this->Internal = NULL;
67  SetInstrumentName(NULL);
68 }
69 
70 //----------------------------------------------------------------------------
71 void vtkPlusThorLabsVideoSource::PrintSelf(ostream& os, vtkIndent indent)
72 {
73  this->Superclass::PrintSelf(os,indent);
74 }
75 
76 //----------------------------------------------------------------------------
77 PlusStatus vtkPlusThorLabsVideoSource::ReadConfiguration(vtkXMLDataElement* rootConfigElement)
78 {
79  LOG_TRACE("vtkPlusThorLabsVideoSource::ReadConfiguration")
80  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement);
81  XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(double, IntegrationTimeSec, deviceConfig);
82  return PLUS_SUCCESS;
83 }
84 
85 //----------------------------------------------------------------------------
86 PlusStatus vtkPlusThorLabsVideoSource::WriteConfiguration(vtkXMLDataElement* rootConfigElement)
87 {
88  LOG_TRACE("vtkPlusThorLabsVideoSource::WriteConfiguration");
89  XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement);
90  deviceConfig->SetFloatAttribute("IntegrationTimeSec", this->IntegrationTimeSec);
91  return PLUS_SUCCESS;
92 }
93 
94 //----------------------------------------------------------------------------
96 {
97  if (this->GetConnected())
98  {
99  // already connected
100  return PLUS_SUCCESS;
101  }
102 
103  ViStatus err = VI_SUCCESS;
104 
105  std::string selectedInstrumentName;
106  if (this->InstrumentName!=NULL && this->InstrumentName[0]!='\0')
107  {
108  selectedInstrumentName = this->InstrumentName;
109  }
110  if (this->InstrumentName==NULL || this->InstrumentName[0]=='\0')
111  {
112  LOG_DEBUG("Scanning for CCS instruments...");
113  ViSession resourceManager = VI_NULL;
114  err = viOpenDefaultRM(&resourceManager);
115  if (err!=VI_SUCCESS)
116  {
117  LOG_ERROR("Error opening ThorLabs resource manager: "<<this->Internal->GetThorLabsErrorString(err));
118  return PLUS_FAIL;
119  }
120  ViChar instrumentNameBuffer[VI_FIND_BUFLEN]={0};
121  ViUInt32 numberOfInstrumentsFound = 0;
122  err = viFindRsrc(resourceManager, TLCCS_FIND_PATTERN, VI_NULL, &numberOfInstrumentsFound, instrumentNameBuffer);
123  if (err!=VI_SUCCESS)
124  {
125  viClose(resourceManager);
126  LOG_ERROR("Error finding ThorLabs resource devices: "<<this->Internal->GetThorLabsErrorString(err));
127  return PLUS_FAIL;
128  }
129  LOG_DEBUG("Found "<<numberOfInstrumentsFound<<" instrument(s). Selected instrument: "<<instrumentNameBuffer);
130  selectedInstrumentName = instrumentNameBuffer;
131  viClose(resourceManager);
132  }
133 
134  err = tlccs_init((char*)selectedInstrumentName.c_str(), VI_OFF, VI_OFF, &this->Internal->InstrumentHandle);
135  if (err!=VI_SUCCESS)
136  {
137  LOG_ERROR("Error opening session to ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
138  return PLUS_FAIL;
139  }
140 
141  err = tlccs_setIntegrationTime(this->Internal->InstrumentHandle, this->IntegrationTimeSec);
142  if (err!=VI_SUCCESS)
143  {
144  LOG_ERROR("Error setting integration time "<< this->IntegrationTimeSec <<"sec in ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
145  tlccs_close(this->Internal->InstrumentHandle);
146  return PLUS_FAIL;
147  }
148 
149  memset(this->Internal->WavelengthIntensityDataBuffer, 0, sizeof(this->Internal->WavelengthIntensityDataBuffer));
150  err = tlccs_getWavelengthData (this->Internal->InstrumentHandle, TLCCS_CAL_DATA_SET_FACTORY, this->Internal->WavelengthIntensityDataBuffer, NULL, NULL);
151  if (err!=VI_SUCCESS)
152  {
153  LOG_ERROR("Error getting wavelength values in ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
154  tlccs_close(this->Internal->InstrumentHandle);
155  return PLUS_FAIL;
156  }
157 
158  // Set frame size (image contains one single line)
159  vtkPlusDataSource* aSource(NULL);
160  if( this->GetFirstVideoSource(aSource) != PLUS_SUCCESS )
161  {
162  LOG_ERROR("Unable to access video source in vtkPlusThorLabsVideoSource. Critical failure.");
163  tlccs_close(this->Internal->InstrumentHandle);
164  return PLUS_FAIL;
165  }
166 
167  aSource->SetInputFrameSize(TLCCS_NUM_PIXELS, 2, 1);
168  aSource->SetPixelType(VTK_DOUBLE);
169  aSource->SetNumberOfScalarComponents(1);
170 
171  return PLUS_SUCCESS;
172 }
173 
175 {
176  // close camera
177  tlccs_close(this->Internal->InstrumentHandle);
178  return PLUS_SUCCESS;
179 }
180 
181 //----------------------------------------------------------------------------
183 {
184  // request device status
185  ViInt32 status = 0;
186  ViStatus err = tlccs_getDeviceStatus(this->Internal->InstrumentHandle, &status);
187  if (err!=VI_SUCCESS)
188  {
189  LOG_ERROR("Error getting device status in ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
190  return PLUS_FAIL;
191  }
192 
193  // camera is idle -> we can trigger a scan
194  if(status & TLCCS_STATUS_SCAN_IDLE)
195  {
196  // trigger scan
197  err = tlccs_startScan(this->Internal->InstrumentHandle);
198  if (err!=VI_SUCCESS)
199  {
200  LOG_ERROR("Error starting scan in ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
201  return PLUS_FAIL;
202  }
203  }
204 
205  // camera has data available for transfer
206  if(status & TLCCS_STATUS_SCAN_TRANSFER)
207  {
208  double* intensityDataBuffer = this->Internal->WavelengthIntensityDataBuffer+TLCCS_NUM_PIXELS; // pointer to the second image line
209  err = tlccs_getScanData(this->Internal->InstrumentHandle, intensityDataBuffer);
210  if (err!=VI_SUCCESS)
211  {
212  LOG_ERROR("Error getting scan data in ThorLabs device: "<<this->Internal->GetThorLabsErrorString(err));
213  return PLUS_FAIL;
214  }
215 
216  vtkPlusDataSource* aSource(NULL);
217  if( this->GetFirstVideoSource(aSource) != PLUS_SUCCESS )
218  {
219  LOG_ERROR("Unable to retrieve the video source in the ThorLabs device.");
220  return PLUS_FAIL;
221  }
222  this->FrameIndex++;
223  FrameSizeType frameSizeInPx = {TLCCS_NUM_PIXELS, 2, 1};
224  aSource->AddItem(this->Internal->WavelengthIntensityDataBuffer, US_IMG_ORIENT_MF, frameSizeInPx, VTK_DOUBLE, 1, US_IMG_BRIGHTNESS, 0, this->FrameIndex);
225  this->Modified();
226  }
227 
228  return PLUS_SUCCESS;
229 }
230 
231 //----------------------------------------------------------------------------
233 {
234  this->FrameIndex = 0;
235  //double startTime = vtkIGSIOAccurateTimer::GetSystemTime();
236  //this->Buffer->SetStartTime(startTime);
237  return PLUS_SUCCESS;
238 }
239 
240 //----------------------------------------------------------------------------
242 {
243  return PLUS_SUCCESS;
244 }
245 
246 //----------------------------------------------------------------------------
248 {
249  if( this->OutputChannels.size() > 1 )
250  {
251  LOG_WARNING("ThorLabsVideoSource is expecting one output channel and there are " << this->OutputChannels.size() << " channels. First output channel will be used.");
252  return PLUS_FAIL;
253  }
254 
255  if( this->OutputChannels.size() == 0 )
256  {
257  LOG_ERROR("No output channels defined for ThorLabs video source. Cannot proceed." );
258  this->CorrectlyConfigured = false;
259  return PLUS_FAIL;
260  }
261 
262  vtkPlusDataSource* aSource(NULL);
263  if( this->GetFirstVideoSource(aSource) != PLUS_SUCCESS )
264  {
265  LOG_ERROR("Unable to retrieve the video source in the ThorLabs device.");
266  return PLUS_FAIL;
267  }
268 
269  // If input image orientation is not set (it is not required) then
270  // set it to MF by default
271  if (aSource->GetInputImageOrientation()==US_IMG_ORIENT_XX)
272  {
273  aSource->SetInputImageOrientation(US_IMG_ORIENT_MF);
274  }
275 
276  return PLUS_SUCCESS;
277 }
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
PlusStatus ReadConfiguration(vtkXMLDataElement *config) override
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_WRITING(deviceConfig, rootConfigElement)
vtkPlusThorLabsVideoSourceInternal * Internal
igsioStatus PlusStatus
Definition: PlusCommon.h:40
PlusStatus SetInputFrameSize(unsigned int x, unsigned int y, unsigned int z)
virtual PlusStatus AddItem(vtkImageData *frame, US_IMAGE_ORIENTATION usImageOrientation, US_IMAGE_TYPE imageType, long frameNumber, double unfilteredTimestamp=UNDEFINED_TIMESTAMP, double filteredTimestamp=UNDEFINED_TIMESTAMP, const igsioFieldMapType *customFields=NULL)
bool RequireImageOrientationInConfiguration
#define PLUS_FAIL
Definition: PlusCommon.h:43
virtual PlusStatus SetInputImageOrientation(US_IMAGE_ORIENTATION imageOrientation)
PlusStatus SetPixelType(igsioCommon::VTKScalarPixelType pixelType)
PlusStatus GetFirstVideoSource(vtkPlusDataSource *&anImage)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
PlusStatus WriteConfiguration(vtkXMLDataElement *config) override
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual US_IMAGE_ORIENTATION GetInputImageOrientation()
bool StartThreadForInternalUpdates
virtual int GetConnected() const
ChannelContainer OutputChannels
PlusStatus SetNumberOfScalarComponents(unsigned int numberOfScalarComponents)
virtual void SetInstrumentName(const char *)
vtkStandardNewMacro(vtkPlusThorLabsVideoSource)
ThorLabs compact spectrometer.
bool CorrectlyConfigured
Interface to a 3D positioning tool, video source, or generalized data stream.