Oscilloscope over WiFi
WhyHow hardware software, scope-side software, client-sideProtocols and interfaces VISA hardware communication subrack/chassis inter-instrument - cables network communication commands and protocols usual network ports mDNS typesVXI-11 RPC channelsUSBTMC (Test & Measurement Class, instrument connection) GPIB interface USB488 registers USB488 subclass - features and capabilities USB488 Trigger message USB488 bulk message usbtmc constants cautionsSCPI (protocol) examples Mandatory SCPI commands for USB488 Optional SCPI/USB488 commands for USB488 binary/bulk data responses nonconforming devices VISA resource name, device addressesSoftware Server side: usbtmc-server.py MODIFICATION: universal_usbtmc FILES Further possible modifications python: usbtmc MODIFICATION FILES Client side: lxi, liblxi MODIFICATIONS FILESRigol DS1054Z notes LAN interface ports network configuration, mDNS enable (fail) LXI vs USBTMC discovery network communication, detailed DISCOVERY, network segment broadcast RPC PORTMAP QUERY VXI-11 call RPC PTP/PictBridge mode (failure?) Windows 10 network and web interface LXI speed speed, LAN/LXI speed, wifi/python/USBTMC SCPI commands data acquisition screenshot waveformRigol DS1052D notes speed, wifi/python/USBTMC SCPI commands data acquisition screenshot waveformConversions and simulations time synchronization PTP, IEEE 1588 Precision Time Protocol GPS as alternative USB-serial Raspberry Pi wireless options triggersSee alsoTodo
Why
Because often it's handy to control oscilloscopes, and other instrumentation, over the network.
Because wireless connection is often more handy than a network cable.
Because cheap Raspberry Pi Zero W can be used to retrofit a USB-only device for full-scale wifi operation.
The implementation is specific for Rigol DS1054Z (and Rigol DS1052D, todo).
How
hardware
The DS1054Z scope has Ethernet and USB. The USB port is a standard instrument driver USB-TMC class interface.
The Ethernet port is a standard LXI interface.
The scope gets a "backpack" with a Raspberry Pi computer. The raspi is connected to the scope by a short USB cable,
accessing the TMC interface.
The raspi may or may not have a display of its own and a touchscreen or set of buttons, for more operations
(sending screenshots and acquired data to the server, server-based protocol decoding, voice annotations,
store banks of configurations, probe gains for nonstandard or ganged-together[1] probes...).
[1] When reverse-engineering mixed signal systems, it's often needed to see both the DC analog level and the weaker
AC signal riding on it. Switching between DC and AC coupling and adjusting the gain for each signal is a pain in the
weknowwhere. Adapter that couples together two channels, and then separate setting of one channel as DC and the other
as more sensitive AC is a good hack, but it halves the input impedance (typ. a megaohm) and screws up the probe
attenuation and the voltages are incorrect. One-touch attenuation setting to the not-in-the-common-list probe value can be handy.
(Also it may be possible to tweak the two-to-one adapter with a trimpot to set up the apparent gain.)
software, scope-side
The raspi needs to run a daemon for the network connectivity, acting as a gateway between a TCP/IP socket
and the TMC device. A python solution was chosen, for flexibility.
Adding functionality to the python daemon will be easy - HTTP-based screenshots and waveform requests, touchscreen interface,
iGornet-class MQTT data feeds...
software, client-side
The "LXI" client, with corresponding "liblxi" library, was chosen.
Protocols and interfaces
The measurement instrumentation is a wild mess of standards old and new, of abstraction layers good and poor.
The standards can be split to the hardware and the software/data halves; the SCPI commands can be relayed through GPIB, USB-TMC, RS232/485, LXI, whatever.
- Instrument Driver - generic name for connection to the instruments; covers the older (1993) VXIplug&play and the newer IVI drivers
Essentially, the hardware/interface/communication standards are about setting up a way to send SCPI messages to the instruments and getting responses; in some
variants also synchronizing time between instruments and sending them triggers.
VISA
VISA - "Virtual instrument software architecture", abstraction layer over different communication standards
- one-size-fits-all, hundreds of megabytes of drivers, clogging the machine with processes, sometimes breaking things
- good for big labs, the usual Windows multihundred-megabyte software bundles are overkill for garage operations with cheap instruments
- the other VISA, not the one that is also about pushing numbers around - this VISA's numbers are real values with real meaning, instead of virtual meaning given only by enough people believing in fiat money
- pyVISA seems to be pretty good lightweight alternative
hardware communication
subrack/chassis
high-speed buses, between instrument cards, within one compact unit - motherboard or backplane and cards
- PXI, "PCI eXtensions for Instrumentation" - high-speed chassis/subrack interconnection for instrumentation cards, based on PCI/CompactPCI
- VXI, "VME eXtensions for Instrumentation" aka ANSI/IEEE 1014-1987, ANSI/VITA 1-1994 - older and slower than PXI
- based on VMEbus, 16bit (later also 32bit and 64bit) parallel bus
- related: VPX aka VITA 46, ANSI/VITA 46.0-2019; STEbus aka IEEE 1000-1987 (8bit data, 20bit address, cheaper than VMEbus, industrial automation, 1980s-1990s before IBM-PC domination)
- many MANY more
inter-instrument - cables
- IEEE-488, aka HP-IB, GPIB - the grandmother of them all; parallel LPT-like bus specific for instrumentation, 8bit, multimaster, multidrop
- RS-232 - plain old serial port - common on older instruments; often essentially SCPI-raw, or SCPI-telnet
- USBTMC, USB with instrumentation class - common on less-ancient instruments
- messages with 12-byte header, same as in the GPIB protocol
- essentially GPIB-over-USB
- USB488 - USBTMC subclass, GPIB/IEEE488 functionality implemented over USB
network communication
over TCP/IP, usually ethernet-based, can be wireless (then beware of unpredictable delays and increased roundtrips)
- LXI, "LAN eXtensions for Instrumentation" - protocols for communication using TCP/IP over local networks
- usually uses either VXI-11 or HiSLIP, can use SCPI-raw
- may implement Precision Time Protocol, IEEE 1588, when timing is necessary - multicast-based timing messages, where NTP is not accurate enough and GPS receivers are costly or impractical
- VXI-11 - a LXI-like specification over SunRPC
- designed to emulate GPIB, including out-of-band signal lines
- port 111 with portmapper, service ports assigned dynamically [ref]
- messages with 12-byte header, same as in the GPIB protocol
- essentially GPIB-over-TCP/IP
- three TCP ports used - core (main SCPI communication), abort (immediate stop of current operation/transaction), interrupt (instrument has asynchronous request)
- HiSLIP, "High Speed LAN Instrument Protocol" - successor of VXI-11
- two connections to port 4880, asynchronous and synchronous channel
- remote COM port - like RS-232 over TCP/IP, raw data with fixed speed at the converter or full RFC-2177
commands and protocols
- SCPI - "Standard Commands for Programmable Instruments"
- based on IEEE 488.2 (1987 and 1992 flavors), a command set of IEEE-488 aka HP-IB aka GPIB
- plaintext commands for communication with instrumentation, hierarchical structure
- ":" as hierarchy separator, on the beginning refers to the root of the command structure, if omitted the command is referred to the "current directory" of the last command
- ends with ? when device is queried, otherwise command is set without expecting response
- space as separator to parameters for command
- eg. :MEAS:VOLT:DC? - measures voltage on DC
usual network ports
https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
- TCP
- 80 - HTTP server, web/browser control of the instrument
- 111 - VXI-11 RPC [link?:portmap] (RFC1833); autodetection (UDP)
- for dynamic assignment of ports for communication, used by VXI11/SICLLAN
- 3537 - (RFC/IANA) "NI-VISA remote"
- 4880 - (RFC/IANA) HiSLIP; usually two connections, for sync and async command stream
- 5024 - (RFC/IANA) SCPI-telnet, SCPI messages encapsulated in RFC855 telnet stream with escape sequences
- 5025 - (RFC/IANA) SCPI-raw, direct SCPI messages
- 5044 - (RFC/IANA) LXI-eventsvc - instrument triggering (see also UDP)
- 5555 - Rigol-brand instruments, SCPI-raw, direct SCPI messages
- 5900 - (RFC/IANA) VNC, remote desktop GUI console
- UDP
- 111 (broadcast) - SunRPC, VXI-11 autodetection
- 319 (multicast, 224.0.1.129/FF02::181) - (RFC/IANA) Precision Time Protocol (IEEE-1588), PTP Events
- 320 (multicast, 224.0.1.129/FF02::181) - (RFC/IANA) Precision Time Protocol (IEEE-1588), PTP General
- 3537 - (RFC/IANA) "NI-VISA remote"
- 5044 (multicast, 224.0.23.159/FF02::138) - (RFC/IANA) LXI-eventsvc - instrument triggering
- 5353 (multicast, 224.0.0.251/FF02::FB) - (RFC/IANA) mDNS - discovery of instruments on the network
mDNS types
- _lxi._tcp
- _vxi-11._tcp
- _scpi-raw._tcp
- _scpi-telnet._tcp
- _hislip._tcp
VXI-11
The VXI-11 protocol is essentially the GPIB interface transferred to Ethernet link.
The functionality is emulated by three network connections:
- core channel (service no. 395183) - SCPI messages come through here
- abort channel - the activity on the core channel is immediately aborted
- interrupt channel - the instrument-initiated messages
The low-level control messages are:
- aborts:
- &ABO (Abort) - Aborts processing of the commands just received.
- &DCL (Device Clear) - Aborts processing of the commands just received and sets the command processing software to a defined initial state. Does not change the instrument setting.
- local/remote (RL1 devices)
- >L (Go to Local) - Transition to the "Local" state (manual control).
- >R (Go to Remote) - Transition to the "Remote" state (remote control).
- &LLO (Local Lockout) - Disables switchover from remote control to manual control by means of the front panel keys.
- &NREN (Not Remote Enable) - Enables switchover from remote control to manual control by means of the front panel keys.
- triggers (DT1 devices), polls
- &GET (Group Execute Trigger) - Triggers a previously active device function (e.g. a sweep). The effect of the command is the same as with that of a pulse at the external trigger signal input.
- &POL (Serial Poll) - Starts a serial poll.
The session setup is fairly involved, beginning with the RPC portmapper call. The SCPI messages are wrapped in the GPIB-derived protocol (very similar to USBTMC).
RPC channels
For whatever reasons, many services do not run on fixed-assigned ports and rely on dynamically assigned ports via a portmapper service.
The most popular one is SunRPC, also called ONC RPC. The portmapper calls request the port of the service via port 111, then connect to
where they were told.
The services requested are identified by a number. Some are:
- 395183 - VXI11 Core Channel (0x0607af) - the requests/responses with the SCPI commands
- 395184 - VXI11 Abort Channel - asynchronous requests to abort operation on core channel
- 395185 - VXI11 Interrupt Channel - asynchronous requests from instrument to host computer
USBTMC (Test & Measurement Class, instrument connection)
Many non-ancient instruments feature a USB-B port (sometimes microUSB), with USB TMC class device.
In Linux, after attachment the device enumerates and forms a /dev/usbtmc* device file. This can be further interfaced with as a character device.
The device behaves similar to usual tty terminals/serial ports with a few important differences. (Eg. usual COM-over-IP attempts won't work.)
The device is usually used to communicate the SCPI command strings and their responses. Eg.
*IDN?
RIGOL TECHNOLOGIES,DS1104Z,DS1ZA210400549,00.04.04.SP4
*IDN?
Rigol Technologies,DS1052D,DS1EC120100007,00.02.02.02.00
GPIB interface
A detour to the ancient era of GPIB, when the features were born.
GPIB Pinout:
data bit 0 DIO1 1 ] [ 13 DIO5 data bit 4
data bit 1 DIO2 2 ] [ 14 DIO6 data bit 5
data bit 2 DIO3 3 ] [ 15 DIO7 data bit 6
data bit 3 DIO4 4 ] [ 16 DIO8 data bit 7
End-or-identify EOI 5 ] [ 17 REN Remote Enable
Data valid DAV 6 ] [ 18 GND/DAV
Not ready for data NRFD 7 ] [ 19 GND/NRFD
No data accepted NDAC 8 ] [ 20 GND/NDAC
Interface clear IFC 9 ] [ 21 GND/IFC
Service request SRQ 10 ] [ 22 GND/SRQ
Attention ATN 11 ] [ 23 GND/ATN
shield 12 ] [ 24 SG signal/logic ground
Uniline commands - single control line involved
- IFC - Interface Clear - clear buffers with pending data
- Remote Enable - enable remote control
- Attention - not in USB
- Identify - not in USB
Multiline commands - 2 or more control lines involved
- Device Clear - clear buffers with pending data
- Local Lockout - send REN_CONTROL and LOCAL_LOCKOUT
- Serial Poll Enable - not in USB
- Serial Poll Disable - not in USB
- Parallel Port Unconfigure - not in USB
Addressed messages - "multicast", addressed by bit flags to one or more devices at once
- GET, Group Execute Trigger
- Selected Device Clear - clear buffers with pending data
- Go To Local - send REN_CONTROL and GO_TO_LOCAL
- Parallel Port Configure - not in USB
- Take Control (not in USB)
Secondary commands
Capabilities:
- AH1 - Acceptor Handshake, can receive remote multiline messages; all USB devices are AH1
- SH1 - Source Handshake, can send multiline messages; all USB devices are SH1
- T6 - Talker - all USB devices are T6
- DC1 - Device Clear - supports device buffer clearing; all USBTMC must be DC1
- C0 - controller - not in USB
- L2/L0 - Listener - can receive device-dependent data; all USB488.2 must be L2, non-USB488.2 can be talk-only (L0)
- DT1/DT0 - Device Trigger - supports trigger
- RL1/RL0 - RemoteLocal - remote control with local lockout
- SR1/SR0 - ServiceRequest - accepts Service Request via interrupt input
USB488 registers
STB, Status Byte:
- bit 7 - OPR (Operation Register Summary)
- bit 6 - MSS (Master Status Summary - MSS=OPR|ESB|MAV)
- bit 5 - ESB (Event Status Summary - ESB=set if any bit set in (ESR AND ESE))
- bit 4 - MAV (Message Available)
- bit 3..0 - 0x00, reserved or various uses
ESR, Event Status Register byte:
- bit 7 - PON = Power ON (set by device power-on event)
- bit 6 - URQ = User Request
- bit 5 - CME = Command Error (undefined mnemonic, bad syntax, or wrong number of param's)
- bit 4 - EXE = Execution Error (command parameter is out of bounds, or wrong data type)
- bit 3 - DDE = Device-Dependent Event (register) summary bit, or Device-Dependent Error
- bit 2 - QYE = Query Error (e.g. the host requested a response without first sending a query message)
- bit 1 - RTL = Returned-To-Local state (RL1 devices only)
- bit 0 - OPC = Operation Completed
ESE, Event Status Enable
- mask for the ESR, to reflect to STB.ESB
- AND ESE with ESR, then set ESB if result nonzero
USB488 subclass - features and capabilities
USB488 is a sub-class of the USBTMC class, implementing various GPIB/IEEE488 features.[ref]
The device is half-duplex. New communication to the instrument must not be sent while there is still a response undelivered.
Each message is prepended by a header, for message synchronization and protection against data loss; a GPIB spec.
USBTMC requests:
- INITIATE_CLEAR - flush device USB buffers
- GET_CAPABILITIES - receives bitmap of capabilities
- interface
- is USB488
- accepts REN_CONTROL, GO_TO_LOCAL, LOCAL_LOCKOUT
- accepts Trigger message
- device
- understands all mandatory SCPI commands - interface must be USB488, device must be SR1-capable
- SR1-capable (ServiceRequest, uses interrupt-in endpoint) - must be set if interface is USB488
- RL1-capable (RemoteLocal, implements remote/local state machine) - interface must accept REN_CONTROL...
- DT1-capable (DeviceTrigger, supports trigger) - interface accepts Trigger
USB488 requests:
- READ_STATUS_BYTE - reads the IEEE488 Status Byte
- REN_CONTROL - Remote Enable
- GO_TO_LOCAL - local control
- LOCAL_LOCKOUT - lock the instrument local control panel, for remote-only
USB488 Trigger message
12-byte message, same size as bulk header; output-to-device only
MsgID - 1 byte - MsgID=128/0x80 for Trigger
cmd - 3 bytes
0x00 - 8 bytes - reserved
USB488 bulk message
a 12-byte header prepended to the USBTMC messages, both to and from the device
MsgID - 1 byte - message identifier
bTag - 1 byte - varies with each transfer
bTagInv - 1 byte - bTag, inverted bits, a form of checksum
0x00 - 1 byte - reserved
size - 4 bytes, LSB first - size of the message
flags - 1 byte - bmTransferAttributes, command-specific flags
0x00 - 3 bytes - reserved
...then the message itself, terminated by \n (0x0a)
...then 0x00 padding to multiple-of-4 length
End of message specified by termination with 0x0a character, and also with EOM bit in flags
usbtmc constants
USB MsgID codes:
USBTMC_MSGID_DEV_DEP_MSG_OUT = 1
USBTMC_MSGID_REQUEST_DEV_DEP_MSG_IN = 2
USBTMC_MSGID_DEV_DEP_MSG_IN = 2
USBTMC_MSGID_VENDOR_SPECIFIC_OUT = 126
USBTMC_MSGID_REQUEST_VENDOR_SPECIFIC_IN = 127
USBTMC_MSGID_VENDOR_SPECIFIC_IN = 127
USB488_MSGID_TRIGGER = 128
result status codes:
USBTMC_STATUS_SUCCESS = 0x01
USBTMC_STATUS_PENDING = 0x02
USBTMC_STATUS_FAILED = 0x80
USBTMC_STATUS_TRANSFER_NOT_IN_PROGRESS = 0x81
USBTMC_STATUS_SPLIT_NOT_IN_PROGRESS = 0x82
USBTMC_STATUS_SPLIT_IN_PROGRESS = 0x83
USB488_STATUS_INTERRUPT_IN_BUSY = 0x20
requests:
USBTMC_REQUEST_INITIATE_ABORT_BULK_OUT = 1
USBTMC_REQUEST_CHECK_ABORT_BULK_OUT_STATUS = 2
USBTMC_REQUEST_INITIATE_ABORT_BULK_IN = 3
USBTMC_REQUEST_CHECK_ABORT_BULK_IN_STATUS = 4
USBTMC_REQUEST_INITIATE_CLEAR = 5
USBTMC_REQUEST_CHECK_CLEAR_STATUS = 6
USBTMC_REQUEST_GET_CAPABILITIES = 7
USBTMC_REQUEST_INDICATOR_PULSE = 64
USB488 request
USB488_READ_STATUS_BYTE = 128
USB488_REN_CONTROL = 160
USB488_GOTO_LOCAL = 161
USB488_LOCAL_LOCKOUT = 162
cautions
Sometimes the device gets to a weird state after a read, and a subsequent read timeouts (timeout in usb/backend/libusb1.py, from self.bulk_in_ep.read in usbtmc/usbtmc.py).
This usually occurs after the device was closed and opened again. Rerunning the command then works again.
Many devices have quirks; Rigol scopes are common with subtle problems or protocol weirdness. Workarounds are often implemented
in drivers and libraries, which is complicated by later firmwares correcting the issue and then not working with the workaround
(eg. Rigol DS1054Z with 00.04.04.SP4 firmware, which needs self.rigol_quirk=False set in usbtmc/usbtmc.py despite setting it True from
the device type autodetection; to add a worm to the can, the firmware revision is not available in the USB data available from the port).
SCPI (protocol)
Standard Commands for Programmable Instruments - general specification for text-based communication protocol,
based on IEEE 488.2 (1987 and 1992 flavors), a command set of IEEE-488 aka HP-IB aka GPIB
Simple one-line commands, hierarchical structure, ":" as hierarchy delimiter, "*" for non-hierarchical command (eg. *IDN?, "identify yourself").
Some devices remember the last "directory" in the hierarchy, others (Rigol DS1054Z, I am looking at YOU!) don't and always require full absolute "paths".
The absolute path starts with ":".
SCPI commands have to tell the instrument they are terminated. Over stream links (TCP socket, serial port, direct character device read/write...) the delimiter is \n aka 0x0a.
In packet connections (USBTMC, UDP...) the message itself can act as its delimiter. Some instruments however require the \n termination even then.
It is safer to use it even if not needed.
Other possible line termination characters/delimiters encountered are \r aka 0x0d, and \0 aka NUL aka 0x00.
In VISA, the delimiters are set by read_termination and write_termination properties of the instrument object.[ref]
The SCPI statements consist of one or more "words", separated by spaces.
The first word can be a query (ends with "?", response from the instrument is expected)
or a command (data are written to the device, operation is performed...).
The statements have optional parameters. For example:
- :DISP:DATA? on,0,png - query screenshot, color, not inverted, in PNG format
- *STB? - query the status byte
- :STOP - stop the scope
- :RUN - ...and run again
- :WAV:STOP 50000 - set the end of the buffer memory to download to 50,000 points
The statements are case-insensitive.
The statements can have a long and short form, often written in mixed case together; DISPlay can be used as both
DISP and DISPLAY (but usually not as DISPL), both upper and lower and mixed case.
Command sets, even for the same general thing, can vary widely, even between devices from the same vendor.
Eg. for sending a screenshot: (from lxi-tools plugins)
- Rigol 1052D/E scopes:
- :HARDCOPY
- :LCD:DATA? (raw 320x234 2:3:3 LCD dump, 74880 bytes)
- Rigol 1000Z-series scopes:
- Rigol 2000 scopes:, Rigol DM3068:
- Rigol DG4000 scopes:
- :HCOPy:SDUMp:DATA:FORMat BMP
- :HCOPy:SDUMp:DATA?
- Rigol DP800:
- Rigol DSA:
- Rohde-Schwarz HMO RTB:
- HCOPy:FORMat BMP
- HCOPy:DATA?
- Keysight multimeter, Keysight IVX:
- :HARDCOPY:INKSAVER OFF
- :DISPLAY:DATA? BMP,COLOR
- Tektronix:
- SAVE:IMAGE:FILEFORMAT PNG
- HARDCOPY:INKSAVER OFF
- HARDCOPY START
- Siglent SDG, SDM3000, SDC, SSA3000x:
Or for acquire memory depth, where DS1052D/E takes :ACQ:MEMD norm/long, and DS1054Z takes :ACQ:MDEP <number>.
Chaos inherent for many-actors system. The only worse situation would be if it'd be designed by a committee.
examples
*IDN?
Rigol Technologies,DS1052D,DS1EC120100007,00.02.02.02.00
DS1052 screenshot
:LCD:DATA?
[raw 74880 bytes]
DS1052 screenshot, more modern firmware (?)
:LCD:DATA?
#9000074880[raw 74880 bytes]
DS1052 waveform buffer data
:WAV:DATA?
[raw 600,8192,16384,524288 or 1048576 bytes]
DS1052 screenshot, more modern firmware (?)
:LCD:DATA?
#9000074880[raw 74880 bytes]
DS1054Z screenshot
:DISP:DATA? ON,0,PNG
#90000xxxxx[raw xxxxx bytes]
DS1054Z waveform buffer data, long form; 600,000 bytes read
:ACQ:MDEP?
600000
:WAV:START 1
:WAV:STOP 250000
:WAV:DATA?
#9000250000[raw 250000 bytes]
:WAV:START 250001
:WAV:STOP 500000
:WAV:DATA?
...and we get an error...
ERR
...so we retry and now succeed...
:WAV:DATA?
#9000250000[raw 250000 bytes]
:WAV:START 500001
:WAV:STOP 600000
:WAV:DATA?
#9000100000[raw 100000 bytes]
run acquisition
:RUN
stop acquisition
:STOP
CAUTION: some commands work only in RUN state, others only in STOP state!
Mandatory SCPI commands for USB488
- *CLS - Clear Status Command - clear all event registers and error queue
- *ESE - Standard event status enable
- *ESE? - Standard event status enable query
- *ESR - Standard event status register query - cleared by reading
- *IDN? - device identification query
- *OPC - Operation Complete command
- *OPC? - Operation Complete query
- *RST - Reset command
- *SRE - Service Request Enable command
- *SRE? - Service Request Enable query
- *STB? - GPIB Status Byte query
- *TRG - Trigger - if device is DT1
- *TST? - self-test query
- *WAI - wait-to-continue command
- *IST? - not in USB - Individual Status query
- *PRE - not in USB - Parallel poll enable register command
- *PRE? - not in USB - Parallel poll enable register query
- *PCB - not in USB - Pass Control Back command
Optional SCPI/USB488 commands for USB488
- *CAL? - Calibration query
- *DDT - Define device trigger command (for DT1 devices)
- *DDT? - Define device trigger query (for DT1 devices)
- *PSC - Power on status clear command
- *PSC? - Power-on status clear query
- *PUD - Protected user data command
- *RDT - Resource description transfer command
- *RDT? - Resource description transfer query
Macro commands
- *DMC - Define macro command
- *EMC - Enable macro command
- *EMC? - Enable macro query
- *GMC? - Get macro contents query
- *LMC? - Learn macro query
- *LRN? - Learn device setup query
- *PMC - Purge macros command
- *RCL - Recall command
- *RMC - Remove individual macro command
- *SAV - Save command
- *SDS - Save default device setting command
binary/bulk data responses
Usually the SCPI command response is a plaintext string. Some types of data (screenshots, raw waveforms...) require a binary blob.
The responses are usually plaintext strings, with numbers as decadic, with exponential notation (eg. 4.546875e-02), and are terminated with newline (\n, 0x0a).
When the response starts with #, it has a different format:
- #Hxxxx - hexadecimal data, newline-terminated
- #Oxxxx - octal data, newline-terminated
- #Bxxxx - binary data, newline-terminated
- #<1-9>nnnnnnnn<binary> - Arbitrary Block Data, newline-terminated
The Arbitrary Block Data is composed of a header and a variable length binary blob of payload:
- #Nnnnnnnnnn[binary data follow] (eg. #9000012345...)
- # - initial signature of the header
- N - number of characters in the payload length (often 9, can be other number between 1..9)
- nnnnnnnnn - payload length, integer as zero-padded ASCII string
Presence of this header at the initial response can be used for continuous read from the source (device, port, socket...) until the payload is all received.
With direct device read from usbtmc/usb488, further binary bytes are present. These are usually stripped by the reading plugin.
The #-something binary data header can be used even with shorter binary data, eg. direct transfer of 32 or 64 bit float numbers
where the ASCII representation could lead to unwanted loss of precision.[ref]
- #70000004<4-bytes> for 32-bit float
The responses, including the binary ones, are always followed by newline character (\n).
nonconforming devices
Some older devices (DS1052, I am looking at YOU!) may not conform and may send the data without the header.
The read routines then do not know when to stop and have to either rely on the known data lengths (possible false positives) or on the read timeout (introduces delay).
VISA resource name, device addresses
The VISA/VXI-11 architecture specifies strings for device addressing. The string uses double colon :: as delimiter
and is composed of:
- interface type (mandatory - USB, TCPIP, GPIB, VXI...), with optional explicit interface number (USB0, USB1, TCPIP1...)
- interface-type specific address (USP VID::PID, IP address with optional TCP port, host address on a bus...)
- optional device or sub-device selection (serial number, interface number, secondary address...)
- resource class (::INSTR, ::SOCKET, ::RAW, ::MEMACC...), default ::INSTR[ref]
The common interfaces are:[ref]
- USB[board]::<VID>::<PID>[::<serialNumber>][::INSTR] - connects to the first (number 0) USBTMC class device
- eg. USB::0x1ab1::0x04ce::INSTR (Rigol DS1054Z)
- eg. USB::0x1ab1::0x04ce::SNXXYYZZAABBCCDD::INSTR (same, with explicit serial number - for more instruments on one machine)
- USB[board]::<VID>::<PID>[::<serialNumber>][::<interfaceNumber>::RAW ]] - raw nonclass USB-device access,
- eg. USB::0x0123::0x4567::SNAABBCCDD::1::RAW - second (number 1) raw USB interface on a device
- TCPIP[board]::<host_address>[::<LAN_device_name>][::INSTR] - uses VXI-11, needs RPC port (111); default LAN device name is inst0 (instr0??)
- eg. TCPIP::10.1.2.3::INSTR - default (instr0) instrument on IP address (or host name)
- eg. TCPIP::10.1.2.3::INSTR3::INSTR - INSTR3 instrument on IP address (or host name)
- TCPIP[board]::<host_address>::<port>::SOCKET - direct socket connection, eg. SCPI-raw
- eg. TCPIP::10.1.2.3::5025::SOCKET - direct connection to SCPI-raw port on IP address (or host name)
- visa://<host_address>[:<port>]/remote_resource - NI-VISA remote instrument
- eg. visa://hostname/ASRL1::INSTR - ASRL1::INSTR exposed on hostname
- ASRL[board][::hostname][::INSTR] - Asynchronous SeRial Line, serial port - COM1, /dev/ttyUSB0...
- eg. ASRL::INSTR1 - COM1
- eg. ASRL::10.1.2.3::1234::INSTR - serial-over-IP serial port, on 10.1.2.3:1234
- eg. ASRL/dev/ttyAMA0::INSTR
Other ones, less common with cheapo instruments, are:
- GPIB (GPIB bus)
- PXI (chassis bus)
- VXI (chassis bus)
Software
For the server (usbtmc-server.py), python was chosen for flexibility and ease of coding.
For the client (liblxi/lxi-tools), C was chosen for the speed of execution (no overhead with loading megabytes of python libraries).
Server side: usbtmc-server.py
for local Rigol DS1054Z scope, exposing SCPI-raw on default port 5025:
python3 ./usbtmc-server.py --backend python_usbtmc USB::0x1ab1::0x04ce::INSTR
the same for Rigol DS1052D (no long-reads):
python3 ./usbtmc-server.py --backend python_usbtmc USB::0x1ab1::0x0588::INSTR
the same for Rigol DS1052D (uses kernel-mode readouts, the reads work):
python3 ./usbtmc-server.py --backend linux_kernel /dev/usbtmc0
Uses several different backends:
- python_usbtmc - local, USBTMC interface (USB VID:PID); similar to VXI-11 protocol
- linux_kernel - local, character device read (eg. /dev/usbtmc0); similar to SCPI-raw protocol
- pyserial - local, serial port (tty or usb-serial - for old and slow devices)
- python_vxi11 - network, connection via portmapper
- tcp_socket - network, direct socket connection
MODIFICATION: universal_usbtmc
The linux_kernel backend had to be modified for the long-data read for the screenshots and data.
On the first read, the beginning of the response is checked if it starts with #<digit>; if not,
do the read as before. If yes, loop through reads until the indicated payload length is read.
FILES
- linux_kernel.py.patch - patch for /usr/local/lib/python3.7/dist-packages/universal_usbtmc/backends/linux_kernel.py
Further possible modifications
The python server can get a thread for listening on HTTP, for commands like screenshots, waveforms, data previews,
save/restore settings, anything else.
Another thread can read buttons or touchscreen.
The scope then will have exposed LXI interface (SCPI-raw), screenshots over HTTP, iGorNet control over MQTT, local buttons/screen control,
arbitrary protocol decoders...
python: usbtmc
Python interface for USBTMC devices, also used by universal_usbtmc.
Handles various device quirks.
In usbtmc/usbtmc.py (eg. /usr/local/lib/python3.7/dist-packages/usbtmc/usbtmc.py), there are detections of quirks of various devices, set as flags
for workarounds in the code. Eg.
- self.advantest_quirk - "Advantest/ADCMT devices have a very odd USBTMC implementation which requires max 63 byte reads and never signals EOI on read; may only send one read packet"
- self.rigol_quirk - "different data flow in multiread communication; Rigol devices only send the header in the first packet, and they lie about whether the transaction is complete"
- self.rigol_quirk_ieee_block - "transfer_size usbtmc header is lying about the transaction size"
MODIFICATION
The self.rigol_quirk was set for the DS1054Z scope, however the 00.04.04.SP4 firmware does not need them.
The setting has to be disabled.
It is possible to modify the library to apply the quirks only for certain serial numbers of devices.
Then the software will behave even for the same devices with different firmwares.
A little more involved code can enable/disable the quirk flags based on the *IDN? response (TODO?).
FILES
- usbtmc.py.patch - for /usr/local/lib/python3.7/dist-packages/usbtmc/usbtmc.py
Client side: lxi, liblxi
https://lxi-tools.github.io/
- liblxi - the underlying library for handling the connections
- lxi-tools - a command for sending/receiving SCPI commands; plugins for screenshots
The lxi command connects to the remote either through VXI-11 (SunRPC over port 111, default) or directly (SCPI-raw over port 5025, option -r; in original lxi
the option applies only to SCPI commands, not to screenshots).
get identification from device "wifiscope" (in /etc/hosts), using raw interface
lxi scpi -r -a wifiscope '*idn?'
get screenshot from device "wifiscope" using rigol-1000z plugin, using raw interface (not in stock lxi)
lxi screenshot -r -p rigol-1000z -a raspidispw screenshot.png
get waveform data (not in stock lxi) from device "wifiscope" using rigol-1000z plugin, using raw interface (not in stock lxi)
lxi getdata -r -p rigol-1000z -a raspidispw wav.bin
MODIFICATIONS
The liblxi was left intact.
The lxi command of lxi-tools got patched to check the beginning of the response if it starts with #<digit>; if not,
do the read as before. If yes, it is the Arbitrary Block Data; loop through reads until the indicated payload length is read.
The screenshot plugin for Rigol 1000Z was amended with this read patch as well.
When the ABD header is not present, the data can be still retrieved using the -L option.
For scpi, the command parsing was modified to allow up to three space-separated arguments. No more need for quotes for simple commands.
Additional options:
- -r in screenshot/getdata: The screenshot plugin got a modification to allow raw access (via port 5025 instead of via port 111 RPC).
- getdata function to acquire waveform: The screenshot plugin was modified for handling the waveform readout. The function differs from sceenshot only by the SCPI command (:DISP:DATA? vs :WAV:DATA?).
- -T,-F,-V,-N in scpi for human-readable output: Time/Frequency/Voltage/None: converts the scientific notation to milli/micro/kilo/mega s/Hz/V/no-units
- -P <port> in screenshot/getdata - explicit port setting for communication (-p is used in scpi, but it is already taken here by plugin); -r defaults to 5025 but Rigol uses 5555
- -d for debugging of the communication; data sent to/from the instrument are shown, when enabled in code the time to first response is also shown
Additional options for DS1052D/E workarounds:
- -D in screenshot/getdata: enable DS1052 quirks (:LCD:DATA? with PNG conversion)
- -C in screenshot: inhibit conversion of raw LCD image in 2:3:3 format to PNG
- -L in scpi/screenshot/getdata: workaround for long reads with arbitrary binary data without # preamble, read until timeout or magic length
- reading stops if the message is 600, 8192, 16384, 74880, 524288, or 1048576 bytes (DS1052 screen wav read, shortmem 2/1 channel, screenshot, longmem 2/1 channel)
- -M in scpi/screenshot/getdata: with -L, allows disabling magic-legth read stops
- the data received usually arrive with block of multiple of (MTU minus packet headers); for MTU=1500 the blocks are 1448 bytes
- the last packet of the transaction has smaller size
- if the (MTU-headers) gives a whole-number multiple of one of the magic sizes, premature transfer stop can occur
The communication of the options to the screenshot plugin is somewhat crude; it is done by making the options.h options structure
accessible from the plugin.
TODO:
- option for specifying max read length for -L
FILES
Patches again lxi-1.21
Rigol DS1054Z notes
LAN interface
ports
- 80 - internal webserver, basic configuration, no real features
- 111 - SunRPC (TCP/UDP), portmapper for VXI-11 communication
- 5555 - SCPI-raw (why not 5025?)
network configuration, mDNS enable (fail)
- web interface on HTTP port 80
- card "Network Settings"
- requires password
- username blank, password "111111" (works here, other reported username is "rigollan")
- enable mDNS, click "apply"...
- ...and the user interface freezes, the IP can't be pinged anymore, the usb requests fail too; probably the controller seizes. (maybe that's why it's passworded?)
- won't be fooled with more, as the usb-over-wifi is intended for operations on wireless networks; the wifi interface requires a standalone computer (Raspi Zero W?) which can as well run mDNS
LXI vs USBTMC
- when USB is connected in USBTMC mode, it takes precedence and LXI via the ethernet port is unavailable
- when USB is connected in PtP mode, LXI is available (todo: actually check, get scope lsusb in ptp mode)
- when USB is disconnected, LXI can operate
- mere connection of the USB cable to the host computer is sufficient for the scope to claim the USBTMC and disable LXI
discovery
lxi discover
Searching for LXI devices - please wait...
Broadcasting on interface lo
Broadcasting on interface eth0
Found "RIGOL TECHNOLOGIES,DS1104Z,DS1ZA210400549,00.04.04.SP4" on address 10.0.0.116
Found 1 device
The master sends a UDP broadcast request to port 111, with a fixed discovery payload.
static char rpc_GETPORT_msg[] =
0x00, 0x00, 0x00, 0x02, 0x00, 0x00,[0x00, 0x03,] 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, [0x00, 0x06, 0x07, 0xaf,]0x00, 0x00, 0x00, 0x01,
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00 };
0x0003 is the GET_PORT RPC call, 0x000607af is the VXI-core channel
Present slaves respond with another UDP packet from their port 111. Master then initiates the "standard"
RPC-mediated VXI-11 "*IDN?" request.
network communication, detailed
DISCOVERY, network segment broadcast
UDP: computer:45106 -> broadcast:111
RPC call: RPCv2, program Portmap (100000) v2, procedyre GETPORT (3)
portmap v2: procedure GETPORT (3), program VXI-11 Core (395183) version 1, proto TCP (6), port 0
UDP: scope:111 -> computer:45106
RPC reply: program Portmap (100000) version 2, procedure GETPORT (3), state=accepted
portmap v2: GETPORT (3) reply, port=618
RPC PORTMAP QUERY
TCP: computer:58770 -> scope:111 OPENING
TCP: computer:58770 -> scope:111
RPC call: RPCv2, program Portmap (100000) v2, procedure GETPORT (3)
portmap v2: procedure GETPORT (3), program VXI-11 Core (395183) version 1, proto TCP (6), port 0
TCP: scope:111 -> computer:58770
RPC reply: program Portmap (100000) version 2, procedure GETPORT (3), state=accepted
portmap v2: GETPORT (3) reply, port=618
TCP: computer:58770 -> scope:111 : CLOSING
VXI-11 call
TCP: computer:791 -> scope:618 : OPENING
TCP: computer:791 -> scope:618
RPC call: RPCv2, program VXI-11 Core (395183) v1, procedure CREATE_LINK (10)
VXI-11 Core Protocol (Create_LinkParms) inst0: procedure CREATE_LINK (10), device name inst0
TCP: scope:618 -> computer:791
RPC reply: program VXI-11 Core (395183) v1, procedure CREATE_LINK (10), state=accepted, AcceptState=RPC executed successfully (0)
VXI-11 Core Protocol (Create_LinkResp) No Error LID=0: error code=no error, abort port=619, max receive size=1500
TCP: computer:791 -> scope:618
RPC call: RPCv2, program VXI-11 Core (395183) v1, procedure DEVICE_WRITE (11)
VXI-11 Core Protocol (Device_WriteParms) LID=0: I/O Timeout=1000, lock timeout=0, flags=0x09 (Wait Until Locked, Set EOI), payload length=6, payload=*IDN?\a
TCP: scope:618 -> computer:791
RPC reply: program VXI-11 Core (395183) v1, procedure DEVICE_WRITE (11), ReplyState=accepted, AcceptState=RPC executed successfully (0)
VXI-11 Core Protocol (Device_WriteResp) No Error: Error Code: no error, size=6
TCP: computer:791 -> scope:618
RPC call: RPCv2, program VXI-11 Core (395183) v1, procedure DEVICE_READ (12)
VXI-11 Core Protocol (Device_ReadParms) LID=0: procedure DEVICE_READ (12), link id=0, size=65536, I/O Timeout=1000, lock timeout=0, flags=0x00, termination char=0x00
TCP: scope:618 -> computer:791
RPC reply: program VXI-11 Core (395183) v1, procedure DEVICE_READ (12)], ReplyState=accepted, AcceptState=RPC executed successfully (0)
VXI-11 Core Protocol (Device_ReadResp) No Error: Error Code: No Error (0), reason=0x04 (END, EOI=true), payload length=55, payload=RIGOL TECHNOLOGIES,DS1104Z,DS1ZA210400549,00.04.04.SP4
TCP: computer:791 -> scope:618
RPC call: RPCv2, program VXI-11 Core (395183) v1, procedure DESTROY_LINK (23)
VXI-11 Core Protocol (Device_Link) LID=0: procedure DESTROY_LINK (23), link id=0
TCP: scope:618 -> computer:791
RPC reply: program VXI-11 Core (395183) v1, procedure DESTROY_LINK (23), ReplyState=accepted, AcceptState=RPC executed successfully (0)
VXI-11 Core Protocol (Device_Error) No Error: procedure DESTROY_LINK (23), error code=No Error (0)
TCP: computer:791 -> scope:618 : CLOSE
RPC
rpcinfo scope
program version netid address service owner
395185 1 tcp 0.0.0.0.2.107 - unknown
395183 1 tcp 0.0.0.0.2.106 - unknown
395184 1 tcp 0.0.0.0.2.105 - unknown
100000 2 tcp 0.0.0.0.0.111 portmapper unknown
100000 2 udp 0.0.0.0.0.111 portmapper unknown
rpcinfo scope -p
program vers proto port service
395185 1 tcp 619
395183 1 tcp 618
395184 1 tcp 617
100000 2 tcp 111 portmapper
100000 2 udp 111 portmapper
nmap for
PORT STATE SERVICE
80/tcp open http
111/tcp open rpcbind
111/udp open rpcbind
617/tcp open sco-dtmgr // RPC-assigned VXI-11 channel, abort
618/tcp open dei-icda // RPC-assigned VXI-11 channel, core
619/tcp open compaq-evm // RPC-assigned VXI-11 channel, interrupt
5353/udp open|filtered zeroconf // mDNS, but doesn't seem to work
5555/tcp open freeciv // Rigol-flavor scpi-raw
6000/udp open|filtered X11
PTP/PictBridge mode (failure?)
Picture Transfer Protocol
The USB interface can be selected to either USBTMC or PTP mode.
gphoto2 --auto-detect
Model Port
----------------------------------------------------------
USB PTP Class Camera usb:001,018
...but gphoto is failing to access the camera, some critical function is apparently not supported by the scope.
Let's try ptpcam from libusb:[ref]...
- get libptp, unpack to somewhere in /usr/src
- apt-get install libusb-dev (configure would cry about libusb-config)
- ./configure (and fill in more missing libraries if needed)
- make (it'll spit some compiler warnings)
- make install
- ldconfig (otherwise ptpcam would complain with "ptpcam: error while loading shared libraries: libptp2.so.1: cannot open shared object file: No such file or directory")
...but ptpcam fails with, drumroll please...
ERROR: Could not get device info!
The ptp_getdeviceinfo call, a PTP_OC_GetDeviceInfo ptp request, does not get through.
The screenshots can be already acquired via LXI or USBTMC, so this is a minor concern.
Apparently the PictBridge thing acts as a client that connects to a server (usually a printer) and sends data to print. The server-side software, which establishes
connection with the PictBridge device (a camera, or here the scope), was too difficult to locate.
Windows 10
The scope becomes visible on USB connection in "Devices and Printers" under "Unspecified" section as "DS1000Z Series". (Driver installation can take a couple minutes.)
In Device Manager, the scope is seen under "Portable devices" as "MTP USB device". Generic WpdMtp driver is apparently used.
In TMC mode, it shows in Device Manager as "USB Test and Measurement Device (IVI)".
network and web interface
Instrument Model: DS1104Z
Manufacturer: RIGOL TECHNOLOGIES
Serial Number: DS1ZA210400549
Description:
LXI Class: LXI Core 2011
LXI Version: 1.4
Host Name:
MAC Address: 00-19-AF-xx-xx-xx
IP Address: 10.0.0.116
Firmware Revision: 00.04.04.SP4
VISA TCP/IP String: TCPIP::10.0.0.116::INSTR
Auto-MDIX Capable: NO
VISA USB Connect String: USB0::0x1AB1::0x4CE::DS1ZA210400549::INSTR
Network Hardware Configuration
Status: CONFIGURED
Password: Not Specified
Link Speed And Duplex Negotiation: Automatic
Link Speed: 100 Mbps
Duplex: Full Automatic
LXI speed
speed, LAN/LXI
direct connection to the network, using ethernet cable and socket on the scope
faster response time than USBTMC/wifi, but lower bulk transfer speed
- almost 3 times faster roundtrip for IDN query
- almost 1/3 slower bulk data transfer for big chunks
- better for
LXI benchmark: 100 ID requests, 154.3 requests/second
action bytes response total
ident 56 0.001 0.02..0.05
screenshot/bmp 1152054 1.67..1.78 1.88..2.00
screenshot/png ~88000 0.05..0.08 0.77..0.81
live data read 1200 0.02..0.05 0.04..0.07
mem read 8192 0.005 0.06..0.11
mem read 16384 0.008 0.07..0.12
mem read 125000 0.34..0.51 0.39..0.65
mem read 250000 0.32..0.67 0.67..0.80 max length of read at once, need to partition to pieces
mem read calculated 524288 ~0.9 ~1.4
mem read calculated 1048576 ~1.8 ~2.8
mem read calculated 12M ~20.2 ~32.2
mem read calculated 24M ~40.3 ~64.3
speed, wifi/python/USBTMC
connected over USBTMC to raspi3, with wifi link over python server as above
LXI benchmark: 100 ID requests, 57.5 requests/second
action bytes response total
ident 56 0.02..0.03 0.04..0.05
screenshot/bmp 1152054 0.97..1.16 1.50..1.64
screenshot/png ~32000 0.53..0.55 0.57..0.60
live data read 1200 0.02..0.05 0.04..0.07
mem read 8192 0.03..0.04 0.05..0.06
mem read 16384 0.03..0.04 0.06..0.08
mem read 125000 0.22..0.24 0.30..0.34
mem read 250000 0.43..0.44 0.55..0.60 max length of read at once, need to partition to pieces
mem read calculated 524288 ~0.9 ~1.1
mem read calculated 1048576 ~1.8 ~2.2
mem read calculated 12M ~20.2 ~25.0
mem read calculated 24M ~40.3 ~49.9
SCPI commands
data acquisition
screenshot
:DISP:DATA? [<color:on/off>,<invert:1/0>,<format:bmp24/bmp8/png/jpeg/tiff>]
- color = on|off
- invert = 1|0
- format = bmp24|bmp8|png|jpeg|tiff (default bmp24)
- common: :DISP:DATA? ON,0,PNG
settings:
- :DISP:TYPE VECT
- :DISP:TYPE DOTS
waveform
- :ACQ:MDEP <memory> - memory depth for a single channel
allowed values (without the commas):
single channel AUTO 12,000 120,000 1,200,000 12,000,000 24,000,000
two channels AUTO 6,000 60,000 600,000 6,000,000 12,000,000
four channels AUTO 3,000 30,000 300,000 3,000,000 6,000,000
Do the change in :RUN mode or the scope will ignore the command. (todo: check)
- :ACQ:TYPE <norm/aver/peak/hres>
- norm - evenly spaced samples
- aver - averaging waveform from multiple samples (:ACQ:AVER)
- peak - shows peak values for the signal envelope; sees tiny pulses but also gets more noise
- hres - high resolution, higher samplerate in converter than for memory, oversampling/averaging
- :ACQ:SRATE? - query current samplerate
- :WAV:SOUR <d0..d15/chan1..chan4/math - waveform source
- :WAV:MODE <norm/max/raw>
- norm - gives data shown on screen (only one that works for MATH)
- max - data on screen when running, memory when stopped
- raw - data from memory (works only when stopped)
- :WAV:FORM <byte/word/asc> - word has MSB=0, ascii takes too much space
- :WAV:START <n> - memory window beginning, first=1
- :WAV:STOP <n> - memory window end
- :WAV:DATA? - read the memory window
- window MUST be at most 250,000 bytes (125,000 words, 15,625 characters)
- iterate through larger windows
Rigol DS1052D notes
Compared to 1054, 1052 is much older and weaker. The most basic SCPI functionality is present; a lot of controls can be done.
The screenshots aren't normally working. The :DISP:DATA? command is not present.
It is however possible to get the raw framebuffer data as a constant-size 320x234 ".raw" image, with 8 bits per pixel, with colors packed
in RR-GGG-BBB scheme (MSB to LSB). Use :HARDCOPY and then :LCD:DATA?.
The firmware revision 00.02.02.02.00 of course does not start the bulk transfers with the #number-length preamble
so read until timeout is needed. Dislike.
The long read from memory seems to be failing with python_usbtmc backend (and works with modified linux_kernel backend).
:ACQ:MEMD LONG/NORMAL works only after next run/stop cycle; :WAV:DATA? done after acq:memd give the length when the memory was acquired.
The scope also has a RS232 port. Its speed is between 9600 and 38400 bps (selectable in menu). While a bit too slow (estimated 20 seconds for a screenshot,
4.5 seconds for 16k memory, and over 4.5 minutes for the megabyte of samples), it is still good enough for using the scope with an arduino.
An "emergency" wireless connection could be made with ESP8266 and serial-to-tcp RFC2177 interface.
speed, wifi/python/USBTMC
Caution: the long memory reads take quite some time, up to 25 seconds for the entire megabyte. This may appear as a timeout to the unwary.
Rough timing of reads, response time (between issuing command and starting receiving data) and total command running time
(against raspi running usbtmc-server.py, over wifi with ping time between 5..12 msec):
LXI benchmark: 100 ID requests, ~22.5 requests/second
action bytes response total
screenshot 74880 1.74-1.77 1.81-1.96 (raw, without compression)
live data read 600 0.03-0.04 0.05-0.06
mem read, 2ch 8192 0.19-0.21 0.21-0.23
mem read, 1ch 16384 0.41-0.43 0.43-0.46
longmem read, 2ch 524288 11.9-12.3 12.1-12.5
longmem read, 1ch 1048576 24.4-24.8 24.9-25.9
SCPI commands
data acquisition
screenshot
:hardcopy (is it necessary?)
:LCD:DATA? (returns 74880 bytes of raw LCD image, 320x234, 8bpp RGB 2:3:3)
Patched LXI can do the conversion to PNG on demand.
TODO: server-side (usbtmc-server.py) emulation of :DISP:DATA? with PNG conversion
waveform
- :ACQ:MEMD <norm/long> - memory depth for a single channel
NORM LONGsingle channel 16384 1048576 (0.2/12.5 seconds read)
two channels 8192 524288 (0.4/25.5 seconds read)
- :ACQ:TYPE <norm/aver/peak>
- :ACQ:AVER <num> - average over samples; can be 2,4,8,16,32,64,128,256
- :ACQ:MODE <rtim/etim> - realtime vs equal time
- :ACQ:SAMP? - get current samplerate
- :WAV:DATA? - get the whole waveform in memory - 600 if running, 8192/16384 if NORMAL mem, 524288/1048576 if LONGMEM
- :WAV:POIN:MODE <norm/max/raw> - memory retrieval
- NORM - screen-only length, 600 bytes; in :RUN and :STOP modes
- RAW - full NORM or LONG memory length; in :STOP mode only
- MAX - gives NORM in :RUN mode, RAW in :STOP mode
The :acq:memd setting reflects to the amount of data read by :wav:data? only after the scope was run, triggered, and stopped.
Other useful commands:
- :KEY:LOCK <enab/dis> - lock/unlock the front panel
- :TRIG:STAT? - trigger status - RUN/STOP/T'D/WAIT/AUTO
- :AUTO - autoguess setting for current input
Conversions and simulations
The LXI/SCPI infrastructure allows very simple interfacing of instrumentation.
E.g. a simple python server can listen on messages from MQTT with data, cache the last one, and serve it on a request.
(Or look up the last value from a log. Or whatever.)
A meteo station then can be implemented as a ESP8266 sensor with periodic MQTT feed, and the measurement can be made
available via eg. ":MEAS:OUTTEMP?" query from standard LabView/MatLab/anything with VISA libraries.
Such "virtual instruments" ("simstruments"?) can be also made visible on the LAN easily via mDNS.
time synchronization
PTP, IEEE 1588 Precision Time Protocol
(do not confuse with Picture Transfer Protocol)
PTP, IEEE 1588, is a tool for time synchronization between devices on a LAN,
similar to but more accurate than NTP and alternative to GPS sync (not needing the receiver
at each node, not needing GPS signal reception).
In linux, it is available as the linuxptp package, with ptp4l command. Uses timemaster to run PTP with NTP
as reference clocks (PTP for precision sync of relative time, NTP for less accurate absolute time).
https://www.nwtime.org/projects/linuxptp/
GPS as alternative
GPS is commonly used to synchronize time of machines. The receivers provide absolute time usually in NMEA-formatted strings
over a serial line, and precision-edge pulse-per-second sync as a separate digital signal. (Take good care about the line
impedance and other transmission line factors when handling this signal; if the edge has to have properly short rise time, the line must not
attenuate even very high frequencies.)
On unix/linux computers, the signal is usually connected to the DCD input of the serial port, as by RFC2783 and
https://www.kernel.org/doc/Documentation/pps/pps.txt.
This PPS sync can be leveraged even without GPS (or the GPS can be simulated completely including the time-bearing NMEA sentences,
using a shared single-Tx-to-many-Rx bus). A master clock can send the PPS (with or without the NMEA), the slaves then take the data as if it was
a real GPS receiver.
USB-serial
USB-serial is polling-based. The interface is queried many times per second. This introduces a possibly significant jitter (up to 125 microseconds
on USB2, much more on USB1).
Raspberry Pi
http://www.unixwiz.net/techtips/raspberry-pi3-gps-time.html
wireless options
The same could be possibly implemented locally via microcontroller-and-nRF24L01 combination. The packets can be delivered one-to-many, the delays
are the same (if retransmissions are disabled, which in one-to-many they have to be anyway as the delivery confirmation would only throw in chaos),
missing a couple packets doesn't throw the local clock off significantly, and it's cheap.
Any other packet radio with low and constant latency will do the job too. Raw pulse-per-second can be sent via a very simple radio too,
with caveats for the rf noise.
For distributed dataloggers, log also some metadata with the timing quality - absent or spurious sync pulses may then help explain
discrepancies in stored data, allow to reliably know the timestamps are unreliable.
Optical methods are also possible, whether free-space or fiber-guided.
triggers
For very high precision, a good shared wire can do the job. Same principle as for the PPS syncing, but missing pulses can be highly
detrimental for the equipment-group operation.
For pulse-based or command-based triggering over wireless, be wary of jitters and especially of missing packets. Wireless, especially 2.4 GHz in urban areas,
can get clogged fairly randomly - usually just the millisecond before DAQ for an unrepeatable test has to be started.
For lower precision, shared-sync clock can do, with a clock offset to trigger at. The offsets then can be unicasted or repeatedly broadcasted
to each equipment piece in advance, with assured delivery of at least one command to each device.
See also
Todo
- USBTMC-to-SCPIraw server
- add mDNS server
- add HTTP screenshot
- add (or make separate) touchscreen daemon
- add VXI-11 support
- RPC support
- encapsulation of in/out messages
- LXI-tools
- options for more advanced waveform saving
- saving to multichannel .WAV file
- retrieval of bulk configurations, together with waveforms or standalone
- auto filenames
- DS1052 extensions as #ifdef
If you have any comments or questions about the topic, please let me know here: |