-
Notifications
You must be signed in to change notification settings - Fork 137
SCPI API design
If you're building a new generation of instrument, or responsible for maintenance of the SCPI protocol stack on an existing instrument family, here's some guidance!
There are a wide range of SCPI implementations across the industry. All of them can be improved in some way or other. Most of the do's (and don'ts) on this list come from real world examples of fielded instruments, however in the interests of neutrality and politeness this document will not mention specific implementations by name. If you are an instrument vendor and are uncertain of which of these items apply to your products, please get in touch and we'll gladly provide personalized guidance.
In general, you should think of SCPI not as an interactive shell or console but as an API, one which happens to be encoded in mostly human readable text. Design for machine consumption.
If you wish to provide an interactive shell for SCPI (including features such as a prompt, command history, echoing of commands typed by the user, in-band error messages, tab complete, etc) you are of course free to do so, but this should be considered separate from your API and run on a separate port.
All other things being equal, your API should be fast. Make commands execute as quickly as possible and avoid unnecessary round trips in the API design.
You should support pipelined transactions (sending multiple commands which execute in sequence as the instrument is ready for them, then sending replies in sequence if necessary). This provides a huge performance boost especially over higher latency connections such as Wi-Fi or VPNs. You do not need gigabytes of receive buffer, but sending several dozen commands in quick succession (such as when replaying a saved instrument configuration to resume a previous experiment) should work.
For example:
(Client) C1:EN
(Client) C2:EN
(Client) C3:EN
(Client) C4:EN
(Client) C1:VDIV?
(Client) C2:VDIV?
(Client) C3:VDIV?
(Client) C4:VDIV?
(Scope) 0.25
(Scope) 0.50
(Scope) 0.125
(Scope) 0.05
You should support multiple concurrent connections (e.g. multiple network clients, or one network client plus a USBTMC session) and use appropriate mutexing and synchronization internally to protect any relevant global state and serialize commands to the hardware.
This is particularly important for instruments that contain multiple logically distinct sub-instruments, such as an oscilloscope and function generator. It is entirely possible that the user may wish to perform automated testing of a DUT using the scope while testing a completely unrelated device, under control of a different piece of software, using the AWG.
Parallel or consecutive sessions should be fully independent at the SCPI protocol layer, with all state tied to that session and destroyed at the end of that session.
All configurable options at the SCPI layer (for example enabling or disabling command echoing, setting 8 or 16 bit waveform transfer format, any sort of "current channel" state used during readback) should be tied to that session and not global to the instrument. It should be possible to have two simultaneous socket connections with these options set differently, and new sessions should always start up with these options in a consistent state regardless of any commands sent by previous sessions.
If the user sends a query and disconnects before reading the reply, the reply should be discarded. It should NOT be held in an internal buffer and sent to a future client, regardless of whether they are connecting via the same interface or a different one. (Sending an API call and getting a reply meant for a prior call leads to the client becoming desynchronized and often renders the instrument unusable from automated tools until it is rebooted or the SCPI stack otherwise resets.)
Things go wrong, this is a fact of life. Users send commands that are not well formed, or are not valid for the current instrument state (e.g. attempting to auto-zero a differential probe when none is connected).