; HP 3478A 5 1/2 Digit DMM
; Tested with Prologix Ethernet GPIB rev 1.2 adapter
; Adapted from Mike Lud's Keysight 344xxA driver
;
; Revision 1.0 	10 Oct 2020		Initial release. 

#metadef
#metadef
#name Hewlett-Packard 3478A
#meta

#author Hexley 
#idString HEWLETT-PACKARD,3478A,
#name HP 3478A
#handle HP3478A
#port GPIB
#driver Ascii

#notes Tested with Prologix Ethernet GPIB rev 1.2 adapter

; A list of possible column name with unit and formatter (SI, Time, Int, D0..D6)
#value VoltageDC V D6 DC_Voltage
#value CurrentDC A si DC_Current
#value VoltageAC V D6 AC_Voltage
#value CurrentAC A si AC_Current
#value Resistance ohm si 2W_Resistance,4W_Resistance


; Simulated SCPI command definitions for the HP3478A

; Function
#scpiCmd DCV tx F1
#scpiCmd ACV tx F2
#scpiCmd 2WO tx F3
#scpiCmd 4WO tx F4
#scpiCmd DCA tx F5
#scpiCmd ACA tx F6

; Range
#scpiCmd RANGE:MIN tx R-3
#scpiCmd RANGE:30MV tx R-2
#scpiCmd RANGE:300MVI tx R-1
#scpiCmd RANGE:3VI tx R0
#scpiCmd RANGE:30VR tx R1
#scpiCmd RANGE:300VR tx R2
#scpiCmd RANGE:3K tx R3
#scpiCmd RANGE:30K tx R4
#scpiCmd RANGE:300K tx R5
#scpiCmd RANGE:3MEG tx R6
#scpiCmd RANGE:30MEG tx R7
#scpiCmd RANGE:AUTO tx R-2RA

; Digits displayed
#scpiCmd DIGITS3 tx N3
#scpiCmd DIGITS4 tx N4
#scpiCmd DIGITS5 tx N5

; Trigger
#scpiCmd TRIG:INTERNAL tx T1
#scpiCmd TRIG:EXTERNAL tx T2
#scpiCmd TRIG:SINGLE tx T3
#scpiCmd TRIG:HOLD tx T4
#scpiCmd TRIG:FAST tx T5

; Autozero
#scpiCmd AZOFF tx Z0
#scpiCmd AZON tx Z1

; Misc. Commands
#scpiCmd READ:SW:POS txrx? S ++read

; Synthetic Commands
#scpiCmd READ:DATA? txrx? ++read eoi

#scpiCmd READ:STATUS:BIN? txrxnBin? 5 B
:readmath: bin(value)

#scpiCmd READ:STATUS? txrxnBin? 5 B

#scpiCmd READ:FUNCTION? txrxnBin? 5 B
:readmath: matchBitsList(value,"001xxxxx",1,"010xxxxx",2,"011xxxxx",3,"100xxxxx",4,"101xxxxx",5,"110xxxxx",6)

#scpiCmd READ:RANGE? txrxnBin? 5 B
:readmath: matchBitsList(value,"001xx",1,"010xx",2,"011xx",3,"100xx",4,"101xx",5,"110xx",6,"111xx",7)

#scpiCmd READ:DIGITS? txrxnBin? 5 B
:readmath: matchBitsList(value,"x01",5,"x10",4, "x11",3)

; HP 3478A Display and Home remaining commands omitted


; How to poll for data, this is used for table and #values?
; a #askMode, #cmdMode and #prepareSample is used before this is string is used.
; This is a single line command
#askValues READ:DATA?

; Format of answer: f=float, u=remove trailing letters, x=skip, *=Zero upper case values if this value is 0
#askValuesReadFormat f

; Accept this delay when reading values (seconds)
#readingDelay 3

; Mode change have a longer delay on reading values (seconds)
#modeChangeDelay 1

; Switch meter to this mode during start, leave empty to avoid any switching
#initialMode

; String to ask about actual meter mode, 
; This is a single line command
#askMode READ:FUNCTION?
 
; Prepare the meter to response to #askValues
#prepareSample

; Initial commands to meter when establishing connection
;#initCmd +llo

; Final command to meter before breaking connection
#finalCmd +loc 

#interfaceType DMM BMM
#interface readValue 0

; Strings to configure device in different modes
#cmdModeLayout 2 3

#cmdMode DC_Voltage 1
DCV

#cmdMode AC_Voltage 2
ACV

#cmdMode 2W_Resistance 3
2WO

#cmdMode 4W_Resistance 4
4WO

#cmdMode DC_Current 5
DCA

#cmdMode AC_Current 6
ACA


; Setup menu functions

;Mode-------------------------------------------------------------------------------------------
#cmdSetup info Active_Mode
:read: READ:FUNCTION?
:readmath: getElement("?; DC Volts;AC Voltage;2W Resistance;4W Resistance;DC Current;AC Current", value)
:updatemodechange:


;DC_Voltage-------------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange DC_Voltage
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range DC_Voltage
:enable: !DC_Voltage.AutoRange.On
:write: (getElement("? RANGE:30MV RANGE:300MVI RANGE:3VI RANGE:30VR RANGE:300VR",value)) 
:read: READ:RANGE?
30mV 1
300mV 2
3V 3
30V 4
300V 5
:updatemodechange:

;AC_Voltage-------------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange AC_Voltage
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range AC_Voltage
:enable: !AC_Voltage.AutoRange.On
:write: (getElement("? RANGE:300MVI RANGE:3VI RANGE:30VR RANGE:300VR",value)) 
:read: READ:RANGE?
300mV 1
3V 2
30V 3
300V 4
:updatemodechange:

;2W_Resistance----------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange a2W_Resistance
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range a2W_Resistance
:enable: !a2W_Resistance.AutoRange.On
:write: (getElement("? RANGE:30VR RANGE:300VR RANGE:3K RANGE:30K RANGE:300K RANGE:3MEG RANGE:30MEG",value)) 
:read: READ:RANGE?
30Ω 1
300Ω 2
3kΩ 3
30kΩ 4
300kΩ 5
3MΩ 6
30MΩ 7
:updatemodechange:

;4W_Resistance----------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange a4W_Resistance
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range a4W_Resistance
:enable: !a4W_Resistance.AutoRange.On
:write: (getElement("? RANGE:30VR RANGE:300VR RANGE:3K RANGE:30K RANGE:300K RANGE:3MEG RANGE:30MEG",value)) 
:read: READ:RANGE?
30Ω 1
300Ω 2
3kΩ 3
30kΩ 4
300kΩ 5
3MΩ 6
30MΩ 7
:updatemodechange:


;DC_Current-------------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange DC_Current
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range DC_Current
:enable: !DC_Current.AutoRange.On
:write: (getElement("? 300MVI 3VI",value))
:read: READ:RANGE?
300mA 1
3A 2
:updatemodechange:

;AC_Current-------------------------------------------------------------------------------------
#cmdSetup checkbox AutoRange AC_Current
:write: (getElement("READ:SW:POS RANGE:AUTO",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxx",0,"1xxxxxxxxx",1)
On 0 1
:updatemodechange:

#cmdSetup comboboxHot Range AC_Current
:enable: !AC_Current.AutoRange.On
:write: (getElement("? 300MVI 3VI",value))
:read: READ:RANGE?
300mA 1
3A 2
:updatemodechange:


;Mode Window Selection-------------------------------------------------------------------------------------
#cmdSetup selector Mode_settings
:read: READ:FUNCTION?
:updatemodechange:
1 DC_Voltage.
2 AC_Voltage.
3 a2W_Resistance.
4 a4W_Resistance.
5 DC_Current.
6 AC_Current.

;Instrument Trigger Settings-------------------------------------------------------------------------------------
#cmdSetup radio Trigger
:write: (getElement("TRIG:INTERNAL TRIG:EXTERNAL TRIG:SINGLE",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"1xxxxxxxx",0,"1xxxxx0xxxxxxxx",1,"0xxxxx0xxxxxxxx",2)
Internal 0
External 1
Single 2
:updatemodechange:

;Instrument Auto-Zero Setting-------------------------------------------------------------------------------------
#cmdSetup checkbox Auto_Zero 
:write: (getElement("AZOFF AZON",value))
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxxx",0,"1xxxxxxxxxx",1)
On 0 1
:updatemodechange:

;Measurement_Terminals-------------------------------------------------------------------------------------------
#cmdSetup info Terminals
:read: READ:STATUS?
:readmath: matchBitsList(value,"0xxxxxxxxxxxx","Rear","1xxxxxxxxxxxx","Front")
:updatemodechange:

