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: 7219fe768465
Choose a base ref
...
head repository: ngscopeclient/scopehal
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 1da41d3d8c12
Choose a head ref
  • 1 commit
  • 2 files changed
  • 1 contributor

Commits on Sep 24, 2020

  1. Very early Tek 5/6 series support. Only reads first block of data so …

    …far. Can't turn channels on/off or do... really almost anything but read waveforms.
    azonenberg committed Sep 24, 2020
    Copy the full SHA
    1da41d3 View commit details
Showing with 168 additions and 47 deletions.
  1. +162 −47 scopehal/TektronixOscilloscope.cpp
  2. +6 −0 scopehal/TektronixOscilloscope.h
209 changes: 162 additions & 47 deletions scopehal/TektronixOscilloscope.cpp
Original file line number Diff line number Diff line change
@@ -43,8 +43,11 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
, m_triggerArmed(false)
, m_triggerOneShot(false)
{
//DEBUG
LogDebug("sizeof(TektronixOscilloscope) = %zu\n", sizeof(TektronixOscilloscope));
//Figure out what device family we are
if( (m_model.find("MSO5") == 0) || (m_model.find("MSO6") == 0) )
m_family = FAMILY_MSO5_6;
else
m_family = FAMILY_UNKNOWN;

/*
//Last digit of the model number is the number of channels
@@ -64,38 +67,44 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
// No header in the reply of queries
m_transport->SendCommand("HEAD 0");

// 8-bit signed data
m_transport->SendCommand("DATA:ENC RIB;WID 1");
//Device specific initialization
switch(m_family)
{
case FAMILY_MSO5_6:
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
break;

default:
// 8-bit signed data
m_transport->SendCommand("DATA:ENC RIB;WID 1");
m_transport->SendCommand("DATA:SOURCE CH1, CH2, CH3, CH4;START 0; STOP 100000");

m_transport->SendCommand("DATA:SOURCE CH1, CH2, CH3, CH4;START 0; STOP 100000");
// FIXME: where to put this?
m_transport->SendCommand("ACQ:STOPA SEQ;REPE 1");
break;
}

// FIXME: where to put this?
m_transport->SendCommand("ACQ:STOPA SEQ;REPE 1");
const char* colors_default[4] = { "#ffff00", "#32ff00", "#5578ff", "#ff0084" }; //yellow-green-violet-pink
const char* colors_mso56[4] = { "#ffff00", "#20d3d8", "#f23f59", "#f16727" }; //yellow-cyan-pink-orange

for(int i=0; i<nchans; i++)
{
//Hardware name of the channel
string chname = string("CH1");
chname[2] += i; // FIXME

//Color the channels based on Tektronix's standard color sequence (yellow-green-violet-pink)
//Color the channels based on Tektronix's standard color sequence
string color = "#ffffff";
switch(i)
switch(m_family)
{
case 0:
color = "#ffff00";
break;

case 1:
color = "#32ff00";
case FAMILY_MSO5_6:
color = colors_mso56[i];
break;

case 2:
color = "#5578ff";
break;

case 3:
color = "#ff0084";
default:
color = colors_default[i];
break;
}

@@ -127,6 +136,8 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
m_channels.push_back(m_extTrigChannel);

//See what options we have
//FIXME: this code is completely broken on MSO5/6
/*
m_transport->SendCommand("*OPT?");
string reply = m_transport->ReadReply();
@@ -153,6 +164,7 @@ TektronixOscilloscope::TektronixOscilloscope(SCPITransport* transport)
{
LogDebug("* %s (unknown)\n", opt.c_str());
}
*/
}

TektronixOscilloscope::~TektronixOscilloscope()
@@ -380,19 +392,16 @@ double TektronixOscilloscope::GetChannelVoltageRange(size_t i)

lock_guard<recursive_mutex> lock2(m_mutex);

// FIXME
return 8;
m_transport->SendCommand(m_channels[i]->GetHwname() + ":SCA?");
string reply = m_transport->ReadReply();
double vdiv;
sscanf(reply.c_str(), "%lf", &vdiv);

#if 0
m_transport->SendCommand(m_channels[i]->GetHwname() + ":RANGE?");
double range = vdiv * 10;

string reply = m_transport->ReadReply();
double range;
sscanf(reply.c_str(), "%lf", &range);
lock_guard<recursive_mutex> lock(m_cacheMutex);
m_channelVoltageRanges[i] = range;
return range;
#endif
}

void TektronixOscilloscope::SetChannelVoltageRange(size_t /*i*/, double /*range*/)
@@ -408,11 +417,6 @@ OscilloscopeChannel* TektronixOscilloscope::GetExternalTrigger()

double TektronixOscilloscope::GetChannelOffset(size_t i)
{
double offset = 0;
m_channelOffsets[i] = offset;
return offset;

#if 0
{
lock_guard<recursive_mutex> lock(m_cacheMutex);

@@ -421,17 +425,16 @@ double TektronixOscilloscope::GetChannelOffset(size_t i)
}

lock_guard<recursive_mutex> lock2(m_mutex);

m_transport->SendCommand(m_channels[i]->GetHwname() + ":OFFS?");

string reply = m_transport->ReadReply();

double offset;
sscanf(reply.c_str(), "%lf", &offset);
offset = -offset;

lock_guard<recursive_mutex> lock(m_cacheMutex);
m_channelOffsets[i] = offset;
return offset;
#endif
}

void TektronixOscilloscope::SetChannelOffset(size_t /*i*/, double /*offset*/)
@@ -451,49 +454,160 @@ Oscilloscope::TriggerMode TektronixOscilloscope::PollTrigger()
m_transport->SendCommand("TRIG:STATE?");
string ter = m_transport->ReadReply();

if(ter == "SAV")
if( (ter == "SAV") || (ter == "SAVE") )
{
m_triggerArmed = false;
return TRIGGER_MODE_TRIGGERED;
}

if(ter != "REA")
if( (ter == "REA") || (ter == "READY") )
{
m_triggerArmed = true;
return TRIGGER_MODE_RUN;
}

//TODO: how to handle auto / normal trigger mode?
//TODO: AUTO, TRIGGER. For now consider that same as RUN
return TRIGGER_MODE_RUN;
}

bool TektronixOscilloscope::AcquireData()
{
//LogDebug("Acquiring data\n");
LogDebug("Acquiring data\n");

lock_guard<recursive_mutex> lock(m_mutex);
LogIndenter li;

//Get record length
size_t length = 0;
char tmp[128];
switch(m_family)
{
case FAMILY_MSO5_6:
{
m_transport->SendCommand("HOR:RECO?");
string reply = m_transport->ReadReply();
sscanf(reply.c_str(), "%zu", &length);

LogDebug("Record length: %zu points\n", length);

snprintf(tmp, sizeof(tmp), "DAT:START 0;DAT:STOP %zu", length);
m_transport->SendCommand(tmp);
}
break;

default:
break;
}

double xincrement = 0;
double ymult = 0;
double yoff = 0;

/*
//unsigned int format;
//unsigned int type;
size_t length;
//unsigned int average_count;
double xincrement;
//double xorigin;
//double xreference;
double yincrement;
double yorigin;
double yreference;
*/
map<int, vector<AnalogWaveform*> > pending_waveforms;
for(size_t i=0; i<m_analogChannelCount; i++)
{
LogDebug("Channel %zu (%s)\n", i, m_channels[i]->GetHwname().c_str());
LogIndenter li2;

if(!IsChannelEnabled(i))
continue;

// Set source & get preamble
m_transport->SendCommand("DATA:SOURCE " + m_channels[i]->GetHwname());
m_transport->SendCommand("WFMPRE:" + m_channels[i]->GetHwname() + "?");
// Set source & get preamble+data
m_transport->SendCommand(string("DAT:SOU ") + m_channels[i]->GetHwname());
switch(m_family)
{
case FAMILY_MSO5_6:
{
//Ask for the waveform preamble and info
m_transport->SendCommand("WAVF?");

//Get the preamble
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)
{
xincrement = stof(reply) * 1e12; //scope gives sec, not ps
//LogDebug("xincrement = %s\n", Unit(Unit::UNIT_PS).PrettyPrint(xincrement).c_str());
}
else if(j == 15)
{
ymult = stof(reply);
//LogDebug("ymult = %s\n", Unit(Unit::UNIT_VOLTS).PrettyPrint(ymult).c_str());
}
else if(j == 17)
{
yoff = stof(reply);
m_channelOffsets[i] = -yoff;
//LogDebug("yoff = %s\n", Unit(Unit::UNIT_VOLTS).PrettyPrint(yoff).c_str());
}
}

//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);

//TODO: seems like we might have more than one block of data to process??

//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 = xincrement;
cap->m_triggerPhase = 0;
cap->m_startTimestamp = time(NULL);
double t = GetTime();
cap->m_startPicoseconds = (t - floor(t)) * 1e12f;
cap->Resize(msglen);

//Convert to volts
for(int j=0; j<msglen; j++)
{
cap->m_offsets[j] = j;
cap->m_durations[j] = 1;
cap->m_samples[j] = ymult*rxbuf[j] + yoff;
}

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

//Done
delete[] rxbuf;

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

default:
//m_transport->SendCommand("WFMPRE:" + m_channels[i]->GetHwname() + "?");
break;
}


/*
// string reply = m_transport->ReadReply();
// sscanf(reply.c_str(), "%u,%u,%lu,%u,%lf,%lf,%lf,%lf,%lf,%lf",
// &format, &type, &length, &average_count, &xincrement, &xorigin, &xreference, &yincrement, &yorigin, &yreference);
@@ -536,13 +650,13 @@ bool TektronixOscilloscope::AcquireData()
m_transport->ReadRawData(2, (unsigned char*)tmp);
tmp[2] = '\0';
int numDigits = atoi(tmp+1);
LogDebug("numDigits = %d", numDigits);
LogDebug("numDigits = %d\n", numDigits);
// Read the number of points
m_transport->ReadRawData(numDigits, (unsigned char*)tmp);
tmp[numDigits] = '\0';
int numPoints = atoi(tmp);
LogDebug("numPoints = %d", numPoints);
LogDebug("numPoints = %d\n", numPoints);
uint8_t* temp_buf = new uint8_t[numPoints / sizeof(uint8_t)];
@@ -565,6 +679,7 @@ bool TektronixOscilloscope::AcquireData()
//Clean up
delete[] temp_buf;
*/
}

//Now that we have all of the pending waveforms, save them in sets across all channels
6 changes: 6 additions & 0 deletions scopehal/TektronixOscilloscope.h
Original file line number Diff line number Diff line change
@@ -112,6 +112,12 @@ class TektronixOscilloscope : public SCPIOscilloscope
void PullEdgeTrigger();
void PushEdgeTrigger(EdgeTrigger* trig);

enum Family
{
FAMILY_MSO5_6,
FAMILY_UNKNOWN
} m_family;

public:
static std::string GetDriverNameInternal();
OSCILLOSCOPE_INITPROC_H(TektronixOscilloscope)