Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: d42ccc80a312
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: b2abc4c446ea
Choose a head ref
  • 2 commits
  • 1 file changed
  • 1 contributor

Commits on Sep 27, 2020

  1. TektronixOscilloscope: very early support for spectrum view. Can disp…

    …lay waveforms but not change frequencies etc. Cannot query gain/offset yet. See #269.
    azonenberg committed Sep 27, 2020
    Copy the full SHA
    a34c06e View commit details
  2. Copy the full SHA
    b2abc4c View commit details
Showing with 120 additions and 37 deletions.
  1. +120 −37 scopehal/TektronixOscilloscope.cpp
157 changes: 120 additions & 37 deletions scopehal/TektronixOscilloscope.cpp
Original file line number Diff line number Diff line change
@@ -81,7 +81,6 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
case FAMILY_MSO6:
m_transport->SendCommand("ACQ:MOD SAM"); //actual sampled data, no averaging etc
m_transport->SendCommand("VERB OFF"); //Disable verbose mode (send shorter commands)
m_transport->SendCommand("DAT:ENC SRI"); //signed, little endian binary
m_transport->SendCommand("ACQ:STOPA SEQ"); //Stop after acquiring a single waveform
m_transport->SendCommand("CONFIG:ANALO:BANDW?"); //Figure out what bandwidth we have
m_bandwidth = stof(m_transport->ReadReply()) * 1e-6; //(so we know what probe bandwidth is)
@@ -143,7 +142,7 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
m_channels.push_back(
new OscilloscopeChannel(
this,
string("CH") + to_string(i+1), //same hwname as the base channel
string("CH") + to_string(i+1) + "_SPECTRUM",
OscilloscopeChannel::CHANNEL_TYPE_ANALOG,
colors_mso56[i % 4],
Unit(Unit::UNIT_HZ),
@@ -390,7 +389,7 @@ bool TektronixOscilloscope::IsChannelEnabled(size_t i)

//Undocumented command to toggle spectrum view state
if(IsSpectrum(i))
m_transport->SendCommand(m_channels[i]->GetHwname() + ":SV:STATE?");
m_transport->SendCommand(m_channels[i - m_spectrumChannelBase]->GetHwname() + ":SV:STATE?");
else
m_transport->SendCommand(string("DISP:WAVEV:") + m_channels[i]->GetHwname() + ":STATE?");
break;
@@ -451,7 +450,7 @@ void TektronixOscilloscope::EnableChannel(size_t i)
case FAMILY_MSO5:
case FAMILY_MSO6:
if(IsSpectrum(i))
m_transport->SendCommand(m_channels[i]->GetHwname() + ":SV:STATE ON");
m_transport->SendCommand(m_channels[i - m_spectrumChannelBase]->GetHwname() + ":SV:STATE ON");
else
m_transport->SendCommand(string("DISP:WAVEV:") + m_channels[i]->GetHwname() + ":STATE ON");
break;
@@ -483,7 +482,7 @@ void TektronixOscilloscope::DisableChannel(size_t i)
case FAMILY_MSO5:
case FAMILY_MSO6:
if(IsSpectrum(i))
m_transport->SendCommand(m_channels[i]->GetHwname() + ":SV:STATE OFF");
m_transport->SendCommand(m_channels[i - m_spectrumChannelBase]->GetHwname() + ":SV:STATE OFF");
else
m_transport->SendCommand(string("DISP:WAVEV:") + m_channels[i]->GetHwname() + ":STATE OFF");
break;
@@ -508,7 +507,7 @@ OscilloscopeChannel::CouplingType TektronixOscilloscope::GetChannelCoupling(size
}

//If not analog, return default
if(i >= m_analogChannelCount)
if(!IsAnalog(i))
return OscilloscopeChannel::COUPLE_DC_50;

OscilloscopeChannel::CouplingType coupling = OscilloscopeChannel::COUPLE_DC_1M;
@@ -573,6 +572,9 @@ OscilloscopeChannel::CouplingType TektronixOscilloscope::GetChannelCoupling(size

void TektronixOscilloscope::SetChannelCoupling(size_t i, OscilloscopeChannel::CouplingType type)
{
if(!IsAnalog(i))
return;

lock_guard<recursive_mutex> lock(m_mutex);

switch(m_family)
@@ -638,7 +640,7 @@ double TektronixOscilloscope::GetChannelAttenuation(size_t i)
}

//If not analog, return default
if(i >= m_analogChannelCount)
if(!IsAnalog(i))
return 1;

lock_guard<recursive_mutex> lock(m_mutex);
@@ -684,6 +686,9 @@ double TektronixOscilloscope::GetChannelAttenuation(size_t i)

void TektronixOscilloscope::SetChannelAttenuation(size_t i, double atten)
{
if(!IsAnalog(i))
return;

{
lock_guard<recursive_mutex> lock(m_cacheMutex);
m_channelAttenuations[i] = atten;
@@ -715,16 +720,16 @@ void TektronixOscilloscope::SetChannelAttenuation(size_t i, double atten)

int TektronixOscilloscope::GetChannelBandwidthLimit(size_t i)
{
//If not analog, return default
if(!IsAnalog(i))
return 0;

{
lock_guard<recursive_mutex> lock(m_cacheMutex);
if(m_channelBandwidthLimits.find(i) != m_channelBandwidthLimits.end())
return m_channelBandwidthLimits[i];
}

//If not analog, return default
if(i >= m_analogChannelCount)
return 0;

int bwl = 0;
{
lock_guard<recursive_mutex> lock(m_mutex);
@@ -768,6 +773,9 @@ int TektronixOscilloscope::GetChannelBandwidthLimit(size_t i)

void TektronixOscilloscope::SetChannelBandwidthLimit(size_t i, unsigned int limit_mhz)
{
if(!IsAnalog(i))
return;

//Update cache
{
lock_guard<recursive_mutex> lock(m_cacheMutex);
@@ -1080,11 +1088,12 @@ bool TektronixOscilloscope::AcquireDataMSO56(map<int, vector<WaveformBase*> >& p
m_transport->SendCommand("DAT:START 0");
m_transport->SendCommand(string("DAT:STOP ") + to_string(length));

map<size_t, double> ymults;
map<size_t, double> yoffs;
double ymult = 0;
double yoff = 0;

//Ask for the analog preambles
//Ask for the analog data
m_transport->SendCommand("DAT:WID 2"); //16-bit data
m_transport->SendCommand("DAT:ENC SRI"); //signed, little endian binary
size_t timebase = 0;
for(size_t i=0; i<m_analogChannelCount; i++)
{
@@ -1111,32 +1120,23 @@ bool TektronixOscilloscope::AcquireDataMSO56(map<int, vector<WaveformBase*> >& p
}
else if(j == 15)
{
ymults[i] = stof(reply);
ymult = stof(reply);
//LogDebug("ymult = %s\n", Unit(Unit::UNIT_VOLTS).PrettyPrint(ymult).c_str());
}
else if(j == 17)
{
yoffs[i] = stof(reply);
m_channelOffsets[i] = -yoffs[i];
yoff = stof(reply);
m_channelOffsets[i] = -yoff;
//LogDebug("yoff = %s\n", Unit(Unit::UNIT_VOLTS).PrettyPrint(yoff).c_str());
}

//TODO: xzero is trigger time
}
}

//Ask for and get the analog data
//(seems like batching here doesn't work)
for(size_t i=0; i<m_analogChannelCount; i++)
{
if(!IsChannelEnabled(i))
continue;

//LogDebug("Channel %zu (%s)\n", i, m_channels[i]->GetHwname().c_str());
LogIndenter li2;

//Read the data blocks
m_transport->SendCommand(string("DAT:SOU ") + m_channels[i]->GetHwname());
m_transport->SendCommand("CURV?");

//Read length of the actual data
@@ -1167,8 +1167,6 @@ bool TektronixOscilloscope::AcquireDataMSO56(map<int, vector<WaveformBase*> >& p
cap->Resize(nsamples);

//Convert to volts
float ymult = ymults[i];
float yoff = yoffs[i];
for(size_t j=0; j<nsamples; j++)
{
cap->m_offsets[j] = j;
@@ -1186,12 +1184,103 @@ bool TektronixOscilloscope::AcquireDataMSO56(map<int, vector<WaveformBase*> >& p
m_transport->ReadReply();
}

//TODO: RF stuff
//CHx_SV_NORMAL,
//CHx_SV_BASEBAND_IQ
//Get the spectrum stuff
m_transport->SendCommand("DAT:WID 8"); //double precision floating point data
m_transport->SendCommand("DAT:ENC SFPB"); //IEEE754 float
for(size_t i=0; i<m_analogChannelCount; i++)
{
auto nchan = m_spectrumChannelBase + i;
if(!IsChannelEnabled(nchan))
continue;

// Set source & get preamble+data
m_transport->SendCommand(string("DAT:SOU ") + m_channels[i]->GetHwname() + "_SV_NORMAL");

//Ask for the waveform preamble
m_transport->SendCommand("WFMO?");

//LogDebug("Channel %zu (%s)\n", nchan, m_channels[nchan]->GetHwname().c_str());
//LogIndenter li2;

//Process it
double hzbase = 0;
for(int j=0; j<22; j++)
{
string reply = m_transport->ReadReply();

//LogDebug("preamble block %d = %s\n", j, reply.c_str());

if(j == 11)
{
hzbase = round(stof(reply));
//LogDebug("xincrement = %s\n", Unit(Unit::UNIT_HZ).PrettyPrint(hzbase).c_str());
}
else if(j == 15)
{
ymult = stof(reply);
//LogDebug("ymult = %s\n", Unit(Unit::UNIT_DBM).PrettyPrint(ymult).c_str());
}
else if(j == 17)
{
yoff = stof(reply);
m_channelOffsets[i] = -yoff;
//LogDebug("yoff = %s\n", Unit(Unit::UNIT_DBM).PrettyPrint(yoff).c_str());
}

//TODO: xzero is trigger time
}

//Read the data block
m_transport->SendCommand("CURV?");

//Read length of the actual data
char tmplen[3] = {0};
m_transport->ReadRawData(2, (unsigned char*)tmplen); //expect #n
int ndigits = atoi(tmplen+1);

char digits[10] = {0};
m_transport->ReadRawData(ndigits, (unsigned char*)digits);
int msglen = atoi(digits);

//Read the actual data
char* rxbuf = new char[msglen];
m_transport->ReadRawData(msglen, (unsigned char*)rxbuf);

//convert bytes to samples
size_t nsamples = msglen/8;
double* samples = (double*)rxbuf;

//Set up the capture we're going to store our data into
//(no TDC data or fine timestamping available on Tektronix scopes?)
AnalogWaveform* cap = new AnalogWaveform;
cap->m_timescale = hzbase;
cap->m_triggerPhase = 0;
cap->m_startTimestamp = time(NULL);
double t = GetTime();
cap->m_startPicoseconds = (t - floor(t)) * 1e12f;
cap->Resize(nsamples);

//We get dBm from the instrument, so just have to convert double to single precision
for(size_t j=0; j<nsamples; j++)
{
cap->m_offsets[j] = j;
cap->m_durations[j] = 1;
cap->m_samples[j] = ymult*samples[j] + yoff;
}

//Done, update the data
pending_waveforms[nchan].push_back(cap);

//Done
delete[] rxbuf;

//Throw out garbage at the end of the message (why is this needed?)
m_transport->ReadReply();
}

//Get the digital stuff
m_transport->SendCommand("DAT:WID 1"); //8 data bits per channel
m_transport->SendCommand("DAT:ENC SRI"); //signed, little endian binary
for(size_t i=0; i<m_analogChannelCount; i++)
{
//Skip anything without a digital probe connected
@@ -1281,12 +1370,6 @@ bool TektronixOscilloscope::AcquireDataMSO56(map<int, vector<WaveformBase*> >& p
m_transport->ReadReply();
}

//Get the spectrum stuff
for(size_t i=0; i<m_analogChannelCount; i++)
{
pending_waveforms[m_spectrumChannelBase + i].push_back(NULL);
}

return true;
}