wip: applet.interface.gpib_command: new applet for GPIB
It's my first applet so there's probably a few things which aren't great - please let me know, happy to fix.
some examples:
$ glasgow run gpib-command -V5 --address 10 --command '*IDN?' --read-eoi
I: g.device.hardware: device already has bitstream ID 9aa1d2585196e6a514d0d0faf2fc5872
I: g.cli: running handler for applet 'gpib-command'
I: g.applet.interface.gpib_command: port(s) A, B voltage set to 5.0 V
TEKTRONIX,TDS 3014,0,CF:91.1CT FV:v2.11 TDS3GM:v1.00 TDS3FFT:v1.00 TDS3TRG:v1.00
$ glasgow run gpib-command -V5 --address 10 --command 'HARDC STAR' --read-eoi > tds3014.eps
I: g.device.hardware: generating bitstream ID 9aa1d2585196e6a514d0d0faf2fc5872
I: g.cli: running handler for applet 'gpib-command'
I: g.applet.interface.gpib_command: port(s) A, B voltage set to 5.0 V
$ eps2png tds3014.eps tds3014.png 1000
how the CLI is structured currently:
- if no address is specified, it'll default to address 0
- if no command is specified, it'll default to listening
- if read-eoi is specified, it'll listen until EOI is asserted. some commands do not respond
Re IRC chat about FSM: How it works
The FSM is divided into three parts: Control, Talk and Listen.
Control starts by sitting idle until a byte is received from out_fifo. The received byte is latched into l_control
-
tx- indicates that a second byte must be latched, this isl_data, and what should be written out to the bus if set. -
eoi- whether to make the EOI line active. This is generally used to signify the last byte of a transmission, although there have been other uses for it. -
ifc- whether to make the IFC line active. This is used to reset all devices on the bus, although the exact purpose may be different between manufacturers. Generally though, if an error has occur on the bus and a device won't respond, setting this for 150uS will reset their error register so the process can restart. Most of the more modern equipment doesn't seem to bother with this. -
ren- whether to make the REN line active. This is "Remote ENable". Some early GPIB equipment would lock out the front panel when under remote control - that would happen automatically if you send a command, but asserting this line is a way to do that without sending a command. -
reserv- this is unused and takes up one bit of space :eyes: -
listen- if set, the FSM will move toListen: Begin- this ignores any of the signalling lines (eoi, ifc, ren) -
talk- if set, the FSM will move toTalk: Begin- this is where signally lines are set. if tx is also set, it'll output the byte latched inl_data.
The next state for "Control: Begin" is always "Control: Read data". If the listen bit was set, it will skip reading data and move onto parse, otherwise latch data, then move to parse.
"Control: Parse" determines what to do next based on the listen and talk bits - if both are asserted it'll move to "Control: Error" (something better needs to happen here). There is one other Control state, "Control: Acknowledge" which is used after talking, but I'll say more on that in a bit.
Talk immediately sets the signalling lines based on l_control. if tx was unset, it'll jump to "Control: Acknowledge", otherwise it'll begin the process of writing to the bus.
Let's talk about GPIB handshaking :sunglasses: There are three handshaking lines: NRFD (Not Ready For Data), NDAC (Not Data Accepted) and DAV (Data Valid). While talking, the controller passively pulls these lines to 5v. Each device has the ability to assert these low (active) by tying them to ground. This enables the speed of the bus to be dictated by the slowest device on the bus.
During transmission, the controller will wait for NDAC to be asserted, the controller can then place data onto the data lines. The FSM uses a small timer to give some time for the data lines to stabilise - this isn't really necessary with short cables, and I haven't found an exact recommended time to wait, but given that GPIB can be wired in both star and bus configuration, or a mixture of the two, it seems like it's worth waiting at least a little.
Once the timer is zero, it'll check to make sure NRFD is not asserted, then assert the DAV line. It'll remain in this state until all devices have unasserted NRFD, and then NDAC. DAV can then be unasserted. Waiting for NRFD and NDAC separately is important, because we need to wait for the slowest device.
The Talk part of the FSM then jumps to "Control: Acknowledge" - Reminder, we can get to "Control: Acknowledge" without doing much "talking", i.e. if tx was unset, resulting in only some signalling lines changing.
"Control: Acknowledge" writes out a single byte GPIBMessage._Acknowledge - this lets the Python side wait for bus to be clear before jumping to (for example) a read, which changes the pull up resistor configuration. So, for each byte written, there's two bytes out and one byte in. (I've actually fixed this slightly by modifying the FSM to skip waiting for the data byte unless it's needed, I don't have my Yubikey to push to github :sob:)
Listen is essentially the same but backwards. NDAC is asserted, NRFD is unasserted - we wait for DAV to be asserted and then move to "Listen: Management lines"
This currently only obtains the state of EOI (so we know if it's the last byte of data), and writes it to in_fifo. Then we move to "Listen: DIO lines" and write the data lines to in_fifo. From python this appears as: ask for data (GPIBMessage.Listen), wait for management (just EOI for now), wait for data. The Listen FSM will wait for unassert NRFD, wait for DAV and then unassert NDAC
:smile:
Things I'd like to add at some point:
- Some kind of timeout for Talking and Listening, since it could just wait forever
- The "Control: Error" will just stay there until reset, maybe that's not too bad if the GPIBInterface presents status nicely.