7 #include "PlusConfigure.h" 10 #include "vtkIGSIOAccurateTimer.h" 15 #include <vtkMatrix4x4.h> 16 #include <vtkSmartPointer.h> 30 class vtkPlusPicoScopeDataSource::vtkInternal
40 ChannelA.channelNumber = 0;
41 ChannelB.channelNumber = 1;
44 virtual ~vtkInternal()
58 MODEL_PS2204A = 0xA204,
59 MODEL_PS2205A = 0xA205
64 PS2000_THRESHOLD_DIRECTION channelA;
65 PS2000_THRESHOLD_DIRECTION channelB;
66 PS2000_THRESHOLD_DIRECTION channelC;
67 PS2000_THRESHOLD_DIRECTION channelD;
68 PS2000_THRESHOLD_DIRECTION ext;
73 PS2000_PWQ_CONDITIONS * conditions;
75 PS2000_THRESHOLD_DIRECTION direction;
78 PS2000_PULSE_WIDTH_TYPE type;
79 } PULSE_WIDTH_QUALIFIER;
92 DIRECTIONS directions;
94 PS2000_TRIGGER_CONDITIONS * conditions;
95 PS2000_TRIGGER_CHANNEL_PROPERTIES * channelProperties;
96 PULSE_WIDTH_QUALIFIER pwq;
97 uint32_t totalSamples;
112 PS2000_RANGE firstRange;
113 PS2000_RANGE lastRange;
114 TRIGGER_CHANNEL trigger;
117 int16_t noOfChannels;
118 int16_t hasAdvancedTriggering;
119 int16_t hasFastStreaming;
121 int16_t hasSignalGenerator;
122 int16_t awgBufferSize;
133 int16_t channelNumber = -1;
134 COUPLING coupling = DC;
136 } PICO_CHANNEL_SETTINGS;
141 std::string GetPicoScopeInfo(
void);
144 PlusStatus RangeIntToEnum(
const int voltageRangeMv, PS2000_RANGE& voltRange);
146 int RangeEnumToInt(
const PS2000_RANGE voltRange);
148 std::string RangeEnumToStr(
const PS2000_RANGE voltRange);
151 std::string GetAdcUnits(int16_t time_units);
154 float AdcToMv(int32_t rawCount, int32_t rangeMv);
160 void PrintChannelInfo(PICO_CHANNEL_SETTINGS channelSettings);
167 int PSInputRanges[PS2000_MAX_RANGES] = { 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000 };
170 PICO_CHANNEL_SETTINGS ChannelA;
171 PICO_CHANNEL_SETTINGS ChannelB;
174 int AppliedNumberOfSamples;
175 int AppliedTimeUnits;
184 std::string PlusSourceId =
"";
189 std::string vtkPlusPicoScopeDataSource::vtkInternal::GetPicoScopeInfo()
191 int8_t description[8][25] = {
"Driver Version ",
205 std::stringstream deviceInfoSS;
207 if (this->Scope.handle)
209 for (
i = 0;
i < 8;
i++)
211 ps2000_get_unit_info(this->Scope.handle,
line,
sizeof(
line),
i);
215 variant = atoi((
const char*)
line);
217 if (strlen((
const char*)
line) == 5)
221 if (
line[1] ==
'2' &&
line[4] ==
'A')
230 deviceInfoSS << description[
i] <<
" " <<
line << std::endl;
237 this->Scope.model = MODEL_PS2104;
238 this->Scope.firstRange = PS2000_100MV;
239 this->Scope.lastRange = PS2000_20V;
240 this->Scope.maxTimebase = PS2104_MAX_TIMEBASE;
241 this->Scope.timebases = this->Scope.maxTimebase;
242 this->Scope.noOfChannels = 1;
243 this->Scope.hasAdvancedTriggering =
false;
244 this->Scope.hasSignalGenerator =
false;
245 this->Scope.hasEts =
true;
246 this->Scope.hasFastStreaming =
false;
250 this->Scope.model = MODEL_PS2105;
251 this->Scope.firstRange = PS2000_100MV;
252 this->Scope.lastRange = PS2000_20V;
253 this->Scope.maxTimebase = PS2105_MAX_TIMEBASE;
254 this->Scope.timebases = this->Scope.maxTimebase;
255 this->Scope.noOfChannels = 1;
256 this->Scope.hasAdvancedTriggering =
false;
257 this->Scope.hasSignalGenerator =
false;
258 this->Scope.hasEts =
true;
259 this->Scope.hasFastStreaming =
false;
263 this->Scope.model = MODEL_PS2202;
264 this->Scope.firstRange = PS2000_100MV;
265 this->Scope.lastRange = PS2000_20V;
266 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
267 this->Scope.timebases = this->Scope.maxTimebase;
268 this->Scope.noOfChannels = 2;
269 this->Scope.hasAdvancedTriggering =
true;
270 this->Scope.hasSignalGenerator =
false;
271 this->Scope.hasEts =
false;
272 this->Scope.hasFastStreaming =
true;
276 this->Scope.model = MODEL_PS2203;
277 this->Scope.firstRange = PS2000_50MV;
278 this->Scope.lastRange = PS2000_20V;
279 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
280 this->Scope.timebases = this->Scope.maxTimebase;
281 this->Scope.noOfChannels = 2;
282 this->Scope.hasAdvancedTriggering =
false;
283 this->Scope.hasSignalGenerator =
true;
284 this->Scope.hasEts =
true;
285 this->Scope.hasFastStreaming =
true;
289 this->Scope.model = MODEL_PS2204;
290 this->Scope.firstRange = PS2000_50MV;
291 this->Scope.lastRange = PS2000_20V;
292 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
293 this->Scope.timebases = this->Scope.maxTimebase;
294 this->Scope.noOfChannels = 2;
295 this->Scope.hasAdvancedTriggering =
true;
296 this->Scope.hasSignalGenerator =
true;
297 this->Scope.hasEts =
true;
298 this->Scope.hasFastStreaming =
true;
302 this->Scope.model = MODEL_PS2204A;
303 this->Scope.firstRange = PS2000_50MV;
304 this->Scope.lastRange = PS2000_20V;
305 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
306 this->Scope.timebases = this->Scope.maxTimebase;
307 this->Scope.noOfChannels = 2;
308 this->Scope.hasAdvancedTriggering =
true;
309 this->Scope.hasSignalGenerator =
true;
310 this->Scope.hasEts =
true;
311 this->Scope.hasFastStreaming =
true;
312 this->Scope.awgBufferSize = 4096;
316 this->Scope.model = MODEL_PS2205;
317 this->Scope.firstRange = PS2000_50MV;
318 this->Scope.lastRange = PS2000_20V;
319 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
320 this->Scope.timebases = this->Scope.maxTimebase;
321 this->Scope.noOfChannels = 2;
322 this->Scope.hasAdvancedTriggering =
true;
323 this->Scope.hasSignalGenerator =
true;
324 this->Scope.hasEts =
true;
325 this->Scope.hasFastStreaming =
true;
329 this->Scope.model = MODEL_PS2205A;
330 this->Scope.firstRange = PS2000_50MV;
331 this->Scope.lastRange = PS2000_20V;
332 this->Scope.maxTimebase = PS2200_MAX_TIMEBASE;
333 this->Scope.timebases = this->Scope.maxTimebase;
334 this->Scope.noOfChannels = 2;
335 this->Scope.hasAdvancedTriggering =
true;
336 this->Scope.hasSignalGenerator =
true;
337 this->Scope.hasEts =
true;
338 this->Scope.hasFastStreaming =
true;
339 this->Scope.awgBufferSize = 4096;
343 LOG_ERROR(
"PicoScope model not supported.");
348 LOG_ERROR(
"Failed to open PicoScope device.");
350 ps2000_get_unit_info(this->Scope.handle,
line,
sizeof(
line), 5);
352 deviceInfoSS << description[5] <<
" " <<
line;
353 this->Scope.model = MODEL_NONE;
354 this->Scope.firstRange = PS2000_100MV;
355 this->Scope.lastRange = PS2000_20V;
356 this->Scope.timebases = PS2105_MAX_TIMEBASE;
357 this->Scope.noOfChannels = 1;
360 return deviceInfoSS.str();
364 PlusStatus vtkPlusPicoScopeDataSource::vtkInternal::RangeIntToEnum(
const int voltageRangeMv, PS2000_RANGE& voltRange)
366 switch (voltageRangeMv)
393 LOG_ERROR(
"Invalid voltage range: " << voltageRangeMv <<
". Ensure you are providing the voltage range in mV.");
399 int vtkPlusPicoScopeDataSource::vtkInternal::RangeEnumToInt(
const PS2000_RANGE voltRange)
431 std::string vtkPlusPicoScopeDataSource::vtkInternal::RangeEnumToStr(
const PS2000_RANGE voltRange)
436 return "PS2000_10MV";
438 return "PS2000_20MV";
440 return "PS2000_50MV";
442 return "PS2000_100MV";
444 return "PS2000_200MV";
446 return "PS2000_500MV";
463 std::string vtkPlusPicoScopeDataSource::vtkInternal::GetAdcUnits(int16_t time_units)
487 float vtkPlusPicoScopeDataSource::vtkInternal::AdcToMv(int32_t rawCount, int32_t rangeMv)
489 return ((
float) (rawCount * rangeMv)) / (PS2000_MAX_VALUE - 1);
493 PlusStatus vtkPlusPicoScopeDataSource::vtkInternal::SetupPicoScopeChannel(vtkInternal::PICO_CHANNEL_SETTINGS settings)
496 if (!settings.enabled)
502 if (!(settings.channelNumber == 0 || (settings.channelNumber == 1 && this->Scope.noOfChannels == 2)))
504 LOG_ERROR(
"Unsupported channel number: " << settings.channelNumber <<
". Check the number of channels your oscilloscope supports. Note: channel numbers start at 0.");
509 if (!ps2000_set_channel(this->Scope.handle, settings.channelNumber,
TRUE, settings.coupling, settings.voltageRange))
511 LOG_ERROR(
"Failed to set PicoScope channel settings for channel: " << settings.channelNumber <<
".");
519 void vtkPlusPicoScopeDataSource::vtkInternal::PrintChannelInfo(PICO_CHANNEL_SETTINGS channelSettings)
521 if (channelSettings.channelNumber == 0)
523 LOG_INFO(
"CHANNEL A Settings:");
525 else if (channelSettings.channelNumber == 1)
527 LOG_INFO(
"CHANNEL B Settings:");
529 LOG_INFO(
"Enabled: " << (channelSettings.enabled ?
"TRUE" :
"FALSE"));
530 LOG_INFO(
"Coupling: " << ((channelSettings.coupling == vtkInternal::DC) ?
"DC" :
"AC"));
531 LOG_INFO(
"Voltage Range: " << this->RangeEnumToStr(channelSettings.voltageRange));
537 , Internal(new vtkInternal(this))
539 LOG_TRACE(
"vtkPlusPicoScopeDataSource::vtkPlusPicoScopeDataSource()");
549 LOG_TRACE(
"vtkPlusPicoScopeDataSource::~vtkPlusPicoScopeDataSource()");
564 LOG_TRACE(
"vtkPlusPicoScopeDataSource::ReadConfiguration");
568 XML_READ_SCALAR_ATTRIBUTE_REQUIRED(
int, NumberOfSamples, deviceConfig);
571 LOG_ERROR(
"Requested number of samples (" << this->NumberOfSamples <<
"( is larger than the maximum number of samples per frame (" <<
MAX_NUM_SAMPLES_PER_FRAME <<
").");
575 XML_FIND_NESTED_ELEMENT_REQUIRED(dataSourcesElement, deviceConfig,
"DataSources");
576 for (
int nestedElementIndex = 0; nestedElementIndex < dataSourcesElement->GetNumberOfNestedElements(); nestedElementIndex++)
578 vtkXMLDataElement* channelDataElement = dataSourcesElement->GetNestedElement(nestedElementIndex);
579 if (STRCASECMP(channelDataElement->GetName(),
"DataSource") != 0)
584 if (channelDataElement->GetAttribute(
"Type") != NULL && STRCASECMP(channelDataElement->GetAttribute(
"Type"),
"Video") != 0)
589 std::string sourceId(channelDataElement->GetAttribute(
"Id"));
590 if (sourceId.empty())
593 LOG_ERROR(
"Failed to initialize PicoScope channel: DataSource Id is missing.");
598 this->Internal->PlusSourceId = sourceId;
601 vtkInternal::COUPLING chA_coupling = vtkInternal::DC;
602 XML_READ_ENUM2_ATTRIBUTE_NONMEMBER_REQUIRED(ChACoupling, chA_coupling, channelDataElement,
"AC", vtkInternal::AC,
"DC", vtkInternal::DC);
603 int chA_voltageRangeMv;
604 XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_REQUIRED(
int, ChAVoltageRangeMv, chA_voltageRangeMv, channelDataElement);
605 PS2000_RANGE chA_voltageRange;
606 if (this->Internal->RangeIntToEnum(chA_voltageRangeMv, chA_voltageRange) !=
PLUS_SUCCESS)
610 this->Internal->ChannelA.enabled =
true;
611 this->Internal->ChannelA.coupling = chA_coupling;
612 this->Internal->ChannelA.voltageRange = chA_voltageRange;
615 vtkInternal::COUPLING chB_coupling = vtkInternal::DC;
616 XML_READ_ENUM2_ATTRIBUTE_NONMEMBER_REQUIRED(ChBCoupling, chB_coupling, channelDataElement,
"AC", vtkInternal::AC,
"DC", vtkInternal::DC);
617 int chB_voltageRangeMv;
618 XML_READ_SCALAR_ATTRIBUTE_NONMEMBER_REQUIRED(
int, ChBVoltageRangeMv, chB_voltageRangeMv, channelDataElement);
619 PS2000_RANGE chB_voltageRange;
620 if (this->Internal->RangeIntToEnum(chB_voltageRangeMv, chB_voltageRange) !=
PLUS_SUCCESS)
624 this->Internal->ChannelB.enabled =
true;
625 this->Internal->ChannelB.coupling = chB_coupling;
626 this->Internal->ChannelB.voltageRange = chB_voltageRange;
635 LOG_TRACE(
"vtkPlusPicoScopeDataSource::WriteConfiguration");
643 LOG_TRACE(
"vtkPlusPicoScopeDataSource::Probe");
644 if (!this->Internal->Scope.handle)
654 LOG_TRACE(
"vtkPlusPicoScopeDataSource::InternalConnect");
657 this->Internal->Scope.handle = ps2000_open_unit();
659 if (!this->Internal->Scope.handle)
662 LOG_ERROR(
"Failed to connect to PicoScope PS2000.");
667 std::string psDeviceInfo;
668 psDeviceInfo += this->Internal->GetPicoScopeInfo();
669 LOG_INFO(
"PicoScope device info: " << std::endl << psDeviceInfo);
673 this->Internal->PrintChannelInfo(this->Internal->ChannelA);
675 this->Internal->PrintChannelInfo(this->Internal->ChannelB);
678 if (this->Internal->SetupPicoScopeChannel(this->Internal->ChannelA) !=
PLUS_SUCCESS)
682 if (this->Internal->SetupPicoScopeChannel(this->Internal->ChannelB) !=
PLUS_SUCCESS)
688 ps2000_set_trigger(this->Internal->Scope.handle, PS2000_NONE, 0, PS2000_RISING, 0, 0);
691 ps2000_set_ets(this->Internal->Scope.handle, PS2000_ETS_OFF, 0, 0);
697 bool timebaseSelected =
false;
699 int32_t timeInterval;
703 for (timebase = 0; timebase <= this->Internal->Scope.maxTimebase; ++timebase)
705 int16_t timebaseResult = ps2000_get_timebase(
706 this->Internal->Scope.handle,
708 this->NumberOfSamples,
715 if (timeInterval == NULL || timeUnits == NULL || maxSamples == NULL)
720 if (timebaseResult != 0 && maxSamples > this->NumberOfSamples)
722 timebaseSelected =
true;
723 this->Internal->AppliedNumberOfSamples = maxSamples;
724 this->Internal->AppliedTimeUnits = timeUnits;
725 this->Internal->AppliedTimebase = timebase;
730 if (!timebaseSelected)
732 LOG_ERROR(
"Failed to select PicoScope timebase. Please choose a different number of samples.");
737 this->
GetVideoSource(this->Internal->PlusSourceId.c_str(), this->Internal->PlusSource);
738 if (this->Internal->PlusSource->GetNumberOfItems() == 0)
740 this->Internal->PlusSource->SetInputImageOrientation(US_IMG_ORIENT_MF);
741 this->Internal->PlusSource->SetImageType(US_IMG_BRIGHTNESS);
742 this->Internal->PlusSource->SetPixelType(VTK_FLOAT);
743 this->Internal->PlusSource->SetNumberOfScalarComponents(1);
744 this->Internal->PlusSource->SetInputFrameSize(this->NumberOfSamples, 3, 1);
753 LOG_TRACE(
"vtkPlusPicoScopeDataSource::InternalDisconnect");
754 ps2000_close_unit(this->Internal->Scope.handle);
759 PlusStatus vtkPlusPicoScopeDataSource::InternalStartRecording()
761 LOG_TRACE(
"vtkPlusPicoScopeDataSource::InternalStartRecording");
767 PlusStatus vtkPlusPicoScopeDataSource::InternalStopRecording()
769 LOG_TRACE(
"vtkPlusPicoScopeDataSource::InternalStopRecording");
777 LOG_TRACE(
"vtkPlusPicoScopeDataSource::InternalUpdate");
780 int32_t timeIndisposedMs;
782 this->Internal->Scope.handle,
783 this->Internal->AppliedNumberOfSamples,
784 this->Internal->AppliedTimebase,
789 while (!ps2000_ready(this->Internal->Scope.handle))
794 const double unfilteredTimestamp = vtkIGSIOAccurateTimer::GetSystemTime();
796 ps2000_stop(this->Internal->Scope.handle);
799 ps2000_get_times_and_values(
800 this->Internal->Scope.handle,
801 this->Internal->Times,
802 this->Internal->SignalARaw,
803 this->Internal->SignalBRaw,
807 this->Internal->AppliedTimeUnits,
808 this->Internal->AppliedNumberOfSamples
813 LOG_WARNING(
"PicoScope overflow occurred in InternalUpdate.");
816 int channelARangeMv = this->Internal->RangeEnumToInt(this->Internal->ChannelA.voltageRange);
817 int channelBRangeMv = this->Internal->RangeEnumToInt(this->Internal->ChannelB.voltageRange);
820 for (
int i = 0;
i < this->NumberOfSamples;
i++)
822 this->Internal->SignalBuffer[
i] = (float)this->Internal->Times[
i];
823 this->Internal->SignalBuffer[
i + this->NumberOfSamples] = this->Internal->AdcToMv(this->Internal->SignalARaw[
i], channelARangeMv);
824 this->Internal->SignalBuffer[
i + 2*this->NumberOfSamples] = this->Internal->AdcToMv(this->Internal->SignalBRaw[
i], channelBRangeMv);
830 LOG_ERROR(
"couldnt find source");
833 FrameSizeType frameSize = { this->NumberOfSamples, 3, 1 };
835 this->Internal->SignalBuffer,
static const int MAX_NUM_SAMPLES_PER_FRAME
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
~vtkPlusPicoScopeDataSource()
Abstract interface for tracker and video devices.
vtkStandardNewMacro(vtkPlusPicoScopeDataSource)
virtual PlusStatus InternalDisconnect()
PlusStatus InternalConnect()
virtual PlusStatus WriteConfiguration(vtkXMLDataElement *config)
PlusStatus InternalUpdate()
void PrintSelf(ostream &os, vtkIndent indent)
unsigned long FrameNumber
virtual PlusStatus ReadConfiguration(vtkXMLDataElement *config)
double InternalUpdateRate
vtkPlusPicoScopeDataSource()
#define XML_FIND_DEVICE_ELEMENT_REQUIRED_FOR_READING(deviceConfig, rootConfigElement)
Interface to the Atracsys trackers This class talks with a Atracsys Tracker over the sTk Passive Trac...
PhidgetVoltageInput_VoltageRange voltageRange
bool StartThreadForInternalUpdates
PlusStatus GetVideoSource(const char *aSourceId, vtkPlusDataSource *&aVideoSource)
Interface to a 3D positioning tool, video source, or generalized data stream.