Thanks for mentioning DSremote, forgot about that one. Installed DSremote in Kubuntu 22.04 LTS, and it takes only 30 seconds to download data in its Wave Inspector.

At first I was trying from Python-IVI, which is a layer on top on PyVISA, as described in the OP. It was way too slow, so this weekend tried sending SCPI commands from C, by calling into the 'liblxi.so' library (liblxi is available in most of the official repos, "sudo apt install liblxi-dev" or from sources at
https://github.com/lxi-tools/liblxi ). Then tried with DSremote, and DSremote is still 3 times faster than anything else I've tried.
Always used RAW mode and BYTES, so 24MB of data to be downloaded for all the 24MSa of ADC data. No matter the size of each consecutive download batches, the duration benchmark is for a complete 24Msa download.
- 23 minutes - Python scripts, IVI calls -> python-ivi -> PyVISA -> PyVISA-py -> python-vxi11 -> LAN -> DS1104Z
- 134 seconds - C program, SCPI requesting batches of 125'000 bytes at once -> lib lxi -> lib tirpc -> LAN -> DS1104Z
- 86 seconds - C program, SCPI requesting batches of 250'000 bytes at once (maximum size according to the DS1000Z programming guide) -> lib lxi -> lib tirpc -> LAN -> DS1104Z
- 65 seconds - C program, SCPI requesting batches of 750'000 bytes at once -> lib lxi -> lib tirpc -> LAN -> DS1104Z
- 55 seconds - C program, SCPI requesting batches of 1'000'000 bytes at once -> lib lxi -> lib tirpc -> LAN -> DS1104Z
- 30 seconds :o - DSremote downloading all the samples to be saved or viewed in its waveform inspector
It's interesting how DSremote is at least twice than any other setup. I've looked at the LAN packets with Wireshark, and it seems DSremote is not using VXI11 protocol for download, it is using plain TCP on the port 5555. The SCPI commands from DSremote are as expected:
STOP:
*OPC?
WAV:SOUR CHAN1
*OPC?
WAV:FORM BYTE
*OPC?
WAV:MODE:RAW
*OPC?
WAV:YINC?
WAV:YREF?
WAV>YOR?
WAV:STAR 1
WAV:OPC?
WAV:STOP 250000
WAV:OPC?
WAV:DATA?
// incoming first 250'000 ADC samples
WAV:STAR 250001\0x0a
*OPC?\0x0a
// (expected response from *OPC is 1\0x0a)
WAV:STOP 500000\0x0a
*OPC?\0x0a
WAV:DATA?\0x0a
// (data response is #9000250000<250kB_of_data_over_many_TCP_packets_of_mostly_65535_TCP_bytes_each>\0x0a
// and so on until all the wanted 24 million samples are fetched
// ...
- SCPI terminator is always the 0x0a char <LF> (beware printf("\n") in Windows is two cars, <CR><LF>, printf("%c", 10) might be safer)
- OPC? (operation completed) is probed by DSremote after each command (which I didn't probe, maybe I should)
- timeout in the DSremote settings was left as found, 50ms, but if I put the same timeout in my C code, the value is too small and leads to timeout errors sooner or later. I had to use 2000ms instead of 50ms.

This is my fastest so far, with C and liblxi, which is still about 3 times slower than DSremote:
// liblxi git at https://github.com/lxi-tools/liblxi
// to install it from the ubuntu repository (lxilib-dev is in most of the Linux distros repos and in FreeBSD):
// sudo apt install liblxi-dev
// headers in /usr/include/lxi.h
// .so lib in /usr/lib/x86_64-linux-gnu/liblxi.so
// display all installed files with 'dpkg -L liblxi-dev' or
// sudo apt install apt-file
// sudo apt-file update
// (sudo???) apt-file list liblxi-dev
// no need to append LIBRRY_PATH or LD_LIBRARY_PATH
// man lxi_<TAB><TAB>
// lxi_connect lxi_discover lxi_init lxi_send lxi_disconnect lxi_discover_if lxi_receive
// compile and run this 'demo.c' from a Linux terminal (!!! -l options _must_ be positioned after the .c sources, not before)
// gcc -Werror -Wfatal-errors ./demo.c -llxi -ltirpc && time ./a.out
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <lxi.h>
int main()
{
// 12 bytes preamble + max of 24 mil bytes of ADC samples + 1 byte for the end of string terminator
#define CHARS_BUFFER_MAX 24000000L // in specs max Rx in a single chunk is 250k chars for Rigol DS1054Z
char *rx24MB = NULL; // declare a pointer to char, and initialize it with NULL
rx24MB = malloc(CHARS_BUFFER_MAX * sizeof *rx24MB); // allocated memory on the heap for rx24MB[CHARS_BUFFER_MAX]
if (!rx24MB) { // !!! always check the memory was allocated successfully !!!
fputs ("ERROR: allocation memory failed for the 'rx24MB' buffer, exiting.", stderr);
exit (EXIT_FAILURE);
}
int device, length, timeout = 2000; // timeout is in ms
char response[1000]; // allocated on the stack, segmentation fault if too large, Linux max stack is 8MiB
char *command = "*IDN?";
lxi_init(); // Initialize LXI library
device = lxi_connect("192.168.1.3", 0, "inst0", timeout, VXI11); // Connect to LXI device
lxi_send(device, command, strlen(command), timeout); // Send SCPI command ("*IDN?")
lxi_receive(device, response, sizeof(response), timeout); // Rx until "\n", or sizeoff(response) chars, or timeout
printf("%s\n", response);
// exit if no DS1054Z
// exit(0);
// enable only ch1
command = ":CHAN1:DISP 1";
lxi_send(device, command, strlen(command), timeout);
command = ":CHAN2:DISP 0";
lxi_send(device, command, strlen(command), timeout);
command = ":CHAN3:DISP 0";
lxi_send(device, command, strlen(command), timeout);
command = ":CHAN4:DISP 0";
lxi_send(device, command, strlen(command), timeout);
// ??? here to insert ":RUN""
// set acquisition mode to max 24_000_000 points memory depth
// "auto", 12K, 120K, 1.2M, 12M, 24M"
long mdep = 24000000L;
command = ":RUN";
lxi_send(device, command, strlen(command), timeout);
// sprintf(command, ":ACQ:MDEP %li", mdep);
// sprintf(command, ":ACQ:MDEP %li%s", mdep, "\0");
command = ":ACQ:MDEP 24000000";
lxi_send(device, command, strlen(command), timeout);
// wait for triggered
do {
command = ":TRIGger:STATus?";
lxi_send(device, command, strlen(command), timeout);
lxi_receive(device, response, sizeof(response), timeout);
} while (response[0] != 'T');
// then wait for ADC to aquire enough data
clock_t stop_time;
printf("wait %ld\n", clock());
stop_time = clock() + 30000; //30 seconds
printf("beep %ld\n", stop_time);
while (clock() < stop_time) ;
printf("go %ld\n", clock());
// go to stop mode and prepare to dl 24MSa
command = ":STOP";
lxi_send(device, command, strlen(command), timeout);
command = ":WAV:SOUR CHAN1";
lxi_send(device, command, strlen(command), timeout);
command = ":WAV:MODE RAW";
lxi_send(device, command, strlen(command), timeout);
command = ":WAV:FORM BYTE";
lxi_send(device, command, strlen(command), timeout);
// char c2[80] = {0};
char c2[80];
// loop to dl all samples in chunks of (max) 250_000 samples
// set start-stop indexes for next chunk
long rx_len, chunk_len;
// long chunk_start, chunk_stop, chunk_size = 125000L; //dl 24Msa/134s
long chunk_start, chunk_stop, chunk_size = 250000L; //dl 24Msa/86s max from specs
// long chunk_start, chunk_stop, chunk_size = 750000L; //dl 24Msa/65s
// long chunk_start, chunk_stop, chunk_size = 1000000L; //dl 24Msa/56s preferred ???
// long chunk_start, chunk_stop, chunk_size = 1175000L; //dl 24Msa/54s
long samples_to_dl = 24000000L;
if (samples_to_dl > mdep) {
samples_to_dl = mdep;
}
for(chunk_start = 1; chunk_start < samples_to_dl; chunk_start += chunk_size) {
sprintf(c2, ":WAV:STAR %li", chunk_start);
puts(c2);
rx_len = lxi_send(device, c2, strlen(c2), timeout);
printf("ack_len=%ld\n", rx_len);
//at the last chunk, chunk_len might be shorter than chunk_size
if (chunk_start + chunk_size > samples_to_dl) {
chunk_len = samples_to_dl - chunk_start + 1;
chunk_stop = samples_to_dl;
} else {
chunk_len = chunk_size;
chunk_stop = chunk_start + chunk_size - 1;
}
sprintf(c2, ":WAV:STOP %li", chunk_stop);
puts(c2);
rx_len = lxi_send(device, c2, strlen(c2), timeout);
printf("ack_len=%ld\n", rx_len);
command = ":WAV:DATA?";
puts(command);
rx_len = lxi_send(device, command, strlen(command), timeout);
printf("ack_len=%ld\n", rx_len);
rx_len = lxi_receive(device, (char *)(&rx24MB[chunk_start-1]), chunk_len, timeout);
printf("rx_data_bytes=%ld\n", rx_len);
int err = 0;
if(rx_len != chunk_len) {
printf("ERROR - received too few bytes: ");
err = 1;
}
printf("chunk_len=%li rx_len=%li\n", chunk_len, rx_len);
printf("\n");
if(err) exit(err);
}
// Disconnect
lxi_disconnect(device);
}
Not sure if I am doing something wrong, or if I should just use TCP instead of VXI11?
