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

Commits on Jan 28, 2021

  1. Copy the full SHA
    d3df0cc View commit details
Showing with 109 additions and 40 deletions.
  1. +65 −17 src/ps6000d/ScpiServerThread.cpp
  2. +41 −21 src/ps6000d/WaveformServerThread.cpp
  3. +3 −2 src/ps6000d/ps6000d.h
82 changes: 65 additions & 17 deletions src/ps6000d/ScpiServerThread.cpp
Original file line number Diff line number Diff line change
@@ -33,47 +33,51 @@
@brief SCPI server. Control plane traffic only, no waveform data.
SCPI commands supported:
*IDN?
Returns a standard SCPI instrument identification string
CHANS?
Returns the number of channels on the instrument.
[chan]:ON
Turns the channel on
[chan]:COUP [DC1M|AC1M|DC50]
Sets channel coupling
[chan]:OFF
Turns the channel off
[chan]:COUP [DC1M|AC1M|DC50]
Sets channel coupling
[chan]:OFFS [num]
Sets channel offset to num volts
[chan]:ON
Turns the channel on
[chan]:RANGE [num]
Sets channel full-scale range to num volts
RATES?
Returns a comma separated list of sampling rates (in femtoseconds)
DEPTH [num]
Sets memory depth
DEPTHS?
Returns the set of available memory depths
EXIT
Terminates the connection
RATE [num]
Sets sample rate
START
Arms the trigger
RATES?
Returns a comma separated list of sampling rates (in femtoseconds)
SINGLE
Arms the trigger in one-shot mode
START
Arms the trigger
STOP
Disarms the trigger
CONNECT
Waits for connection on the data plane socket
EXIT
Terminates the connection
*/

#include "ps6000d.h"
@@ -103,8 +107,9 @@ size_t g_captureMemDepth = 0;

uint32_t g_timebase = 0;

volatile bool g_triggerArmed = false;
volatile bool g_triggerOneShot = false;
bool g_triggerArmed = false;
bool g_triggerOneShot = false;
bool g_memDepthChanged = false;

void UpdateChannel(size_t chan);

@@ -224,6 +229,38 @@ void ScpiServerThread()
ScpiSend(client, ret);
}

//Get memory depths
else if(cmd == "DEPTHS")
{
string ret = "";

lock_guard<mutex> lock(g_mutex);
double intervalNs;
size_t maxSamples;

//Ask for max memory depth at 1.25 Gsps. Why does legal memory depend on sample rate?
if(PICO_OK == ps6000aGetTimebase(g_hScope, 2, 1, &intervalNs, &maxSamples, 0))
{
//Seems like there's no restrictions on actual memory depth other than an upper bound.
//To keep things simple, report 1-2-5 series from 10K samples up to the actual max depth

for(size_t base = 10000; base < maxSamples; base *= 10)
{
const size_t muls[] = {1, 2, 5};
for(auto m : muls)
{
size_t depth = m * base;
if(depth < maxSamples)
ret += to_string(depth) + ",";
}
}

ret += to_string(maxSamples) + ",";
}

ScpiSend(client, ret);
}

else
LogDebug("Unrecognized query received: %s\n", line.c_str());
}
@@ -351,6 +388,8 @@ void ScpiServerThread()

else if( (cmd == "RATE") && (args.size() == 1) )
{
lock_guard<mutex> lock(g_mutex);

//Convert sample rate to sample period
auto rate = stoull(args[0]);
g_sampleInterval = 1e15 / rate;
@@ -367,6 +406,12 @@ void ScpiServerThread()
g_timebase = timebase;
}

else if( (cmd == "DEPTH") && (args.size() == 1) )
{
lock_guard<mutex> lock(g_mutex);
g_memDepth = stoull(args[0]);
}

else if( (cmd == "START") || (cmd == "SINGLE") )
{
lock_guard<mutex> lock(g_mutex);
@@ -390,6 +435,9 @@ void ScpiServerThread()
continue;
}

if(g_captureMemDepth != g_memDepth)
g_memDepthChanged = true;

g_channelOnDuringArm = g_channelOn;
g_captureMemDepth = g_memDepth;
g_sampleIntervalDuringArm = g_sampleInterval;
62 changes: 41 additions & 21 deletions src/ps6000d/WaveformServerThread.cpp
Original file line number Diff line number Diff line change
@@ -51,34 +51,18 @@ void WaveformServerThread()

//Set up buffers
map<size_t, int16_t*> waveformBuffers;
for(size_t i=0; i<g_numChannels; i++)
{
lock_guard<mutex> lock(g_mutex);

//Allocate memory if needed
waveformBuffers[i] = new int16_t[g_memDepth];
memset(waveformBuffers[i], 0x00, g_memDepth * sizeof(int16_t));

//Give it to the scope
auto status = ps6000aSetDataBuffer(g_hScope, (PICO_CHANNEL)i, waveformBuffers[i],
g_memDepth, PICO_INT16_T, 0, PICO_RATIO_MODE_RAW, PICO_ADD);
if(status != PICO_OK)
{
LogFatal("ps6000aSetDataBuffer failed (code %d)\n", status);
}
}

size_t numSamples = 0;
uint16_t numchans;
while(!g_waveformThreadQuit)
{
int16_t status;
int16_t ready;
{
lock_guard<mutex> lock(g_mutex);
ps6000aIsReady(g_hScope, &status);
ps6000aIsReady(g_hScope, &ready);
}

if( (status == 0) || (!g_triggerArmed) )
if( (ready == 0) || (!g_triggerArmed) )
{
usleep(1000);
continue;
@@ -90,10 +74,38 @@ void WaveformServerThread()
//Stop the trigger
ps6000aStop(g_hScope);

//Set up buffers if needed
if(g_memDepthChanged || waveformBuffers.empty())
{
LogDebug("Reallocating buffers\n");

for(size_t i=0; i<g_numChannels; i++)
{
ps6000aSetDataBuffer(g_hScope, (PICO_CHANNEL)i, NULL,
0, PICO_INT16_T, 0, PICO_RATIO_MODE_RAW, PICO_CLEAR_ALL);
}
for(size_t i=0; i<g_numChannels; i++)
{
//Allocate memory if needed
if(waveformBuffers[i])
delete[] waveformBuffers[i];
waveformBuffers[i] = new int16_t[g_captureMemDepth];
memset(waveformBuffers[i], 0x00, g_captureMemDepth * sizeof(int16_t));

//Give it to the scope, removing any other buffer we might have
auto status = ps6000aSetDataBuffer(g_hScope, (PICO_CHANNEL)i, waveformBuffers[i],
g_captureMemDepth, PICO_INT16_T, 0, PICO_RATIO_MODE_RAW, PICO_ADD);
if(status != PICO_OK)
LogFatal("ps6000aSetDataBuffer failed (code %d)\n", status);
}

g_memDepthChanged = false;
}

//Download the data from the scope
numSamples = g_captureMemDepth;
int16_t overflow = 0;
status = ps6000aGetValues(g_hScope, 0, &numSamples, 1, PICO_RATIO_MODE_RAW, 0, &overflow);
auto status = ps6000aGetValues(g_hScope, 0, &numSamples, 1, PICO_RATIO_MODE_RAW, 0, &overflow);
if(PICO_OK != status)
LogFatal("ps6000aGetValues (code %d)\n", status);

@@ -137,14 +149,22 @@ void WaveformServerThread()
{
lock_guard<mutex> lock(g_mutex);

if(g_captureMemDepth != g_memDepth)
g_memDepthChanged = true;

g_channelOnDuringArm = g_channelOn;
g_captureMemDepth = g_memDepth;
g_sampleIntervalDuringArm = g_sampleInterval;

//Restart
status = ps6000aRunBlock(g_hScope, g_captureMemDepth/2, g_captureMemDepth/2, g_timebase, NULL, 0, NULL, NULL);
auto status = ps6000aRunBlock(g_hScope, g_captureMemDepth/2, g_captureMemDepth/2,
g_timebase, NULL, 0, NULL, NULL);
if(status != PICO_OK)
LogFatal("ps6000aRunBlock in WaveformServerThread failed, code %d\n", status);
}
}

//Clean up temporary buffers
for(auto it : waveformBuffers)
delete[] it.second;
}
5 changes: 3 additions & 2 deletions src/ps6000d/ps6000d.h
Original file line number Diff line number Diff line change
@@ -69,8 +69,9 @@ extern uint32_t g_timebase;
extern int64_t g_sampleInterval;
extern int64_t g_sampleIntervalDuringArm;

extern volatile bool g_triggerArmed;
extern volatile bool g_triggerOneShot;
extern bool g_triggerArmed;
extern bool g_triggerOneShot;
extern bool g_memDepthChanged;

extern std::mutex g_mutex;