; known issues:
; XXX after RCL-ing stored parameters,
; only mode can be fetched with :FUNC?
; Voltage, current, resistance and power cannot be retrieved with
; :VOLT? CURR? RES? or POW?
; Probably firmware bug.
; -----------------------------------------------------------------------------    
#metadef
#author tgotic
#idString RND,KEL103,
#name RND KEL103v2
#handle KEL103v2
; -----------------------------------------------------------------------------
; min & max values
; -----------------------------------------------------------------------------
#replaceText DeviceMinVoltage     0.1
#replaceText DeviceMaxVoltage     120
#replaceText DeviceMaxCurrent     30
#replaceText DeviceMinRate        0.0001
#replaceText DeviceMaxRate        1.5
#replaceText DeviceMaxPower       300
#replaceText DeviceMinResistance  0.05
#replaceText DeviceMaxResistance  7500
; -----------------------------------------------------------------------------
#meta
#author tgotic
#idString RND,KEL103,
#name RND KEL103v2
#handle KEL103v2
#port com 18190u
#driver SCPIx
#baudrate 115200
#notes Use serial connection to setup network parameters.
UPD network is unreliable, this means there is no guarantee that commands or answer are received. On a low traffic local network the probability is good it will work.
The advanced modes on the load must be started from the command line.
; -----------------------------------------------------------------------------
; *IDN?
; -----------------------------------------------------------------------------
; Fix *idn? by adding commas and swapping serial number and version
#scpiCmd *idn? *IDN?
:readmath: var v=split(value,"[- ]");v[0]+","+v[2]+","+replace(v[4],"S","")+","+replace(v[3],"V","");
;RND 320-KEL103 V2.10 S12345678  ->  RND,320,V2.10,KEL103

; -----------------------------------------------------------------------------
; command definitions
; -----------------------------------------------------------------------------
#scpiCmd dev:init :SYST:LOCK 1
#scpiCmd dev:fini :INP OFF;:SYST:LOCK 0

#scpiCmd capacity? :BATT:CAP?

#scpiCmd time? :BATT:TIM?
:readmath: (getMatch(value,"[0-9.]+"))*100

#scpiCmd voltage? :MEAS:VOLT?
#scpiCmd current? :MEAS:CURR?
#scpiCmd power? :MEAS:POW?

#scpiCmd voltage:limits :VOLT:UPP (getElement(value,1))
#scpiCmd current:limits :CURR:UPP (getElement(value,1))
#scpiCmd power:limits :POW:UPP (getElement(value,1))
#scpiCmd resistance:limits :RES:UPP (getElement(value,1))

#scpiCmd mode? :FUNC?
:readmath: replace(replace(replace(value,"TOGGLE","DYN_P"),"PULSE","DYN_T"),"CONTINUOUS ","DYN_");
:setvar: deviceMode=value

#scpiCmd dyn:cv? (varExists("deviceMode")?((deviceMode)=="DYN_CV"?":DYN?":""):"")
:readmath: replace(value,"%",""); 
#scpiCmd dyn:cr? (varExists("deviceMode")?((deviceMode)=="DYN_CR"?":DYN?":""):"")
:readmath: replace(value,"%",""); 
#scpiCmd dyn:cw? (varExists("deviceMode")?((deviceMode)=="DYN_CW"?":DYN?":""):"")  
:readmath: replace(value,"%","");  
#scpiCmd dyn:cc? (varExists("deviceMode")?((deviceMode)=="DYN_CC"?":DYN?":""):"")
:readmath: replace(replace(value,"/",""),"%","");
;replace % and / in A/uS so :readformat: u can remove letters
 
#scpiCmd dyn:pulse? (varExists("deviceMode")?((deviceMode)=="DYN_P"?":DYN?":""):"")  
:readmath: replace(value,"/","");
  
#scpiCmd dyn:toggle? (varExists("deviceMode")?((deviceMode)=="DYN_T"?":DYN?":""):"")   
:readmath: replace(value,"/","");

#scpiCmd rcl:battery :RCL:BATT (value)
:setvar: selBattery=inputValue

#scpiCmd rcl:battery:mode :RCL:BATT (varExists("selBattery")?(selBattery):1)
#scpiCmd sav:battery :BATT (varExists("selBattery")?(selBattery):1,(value))

#scpiCmd rcl:ocp :RCL:OCP (value)
:setvar: selOCP=inputValue

#scpiCmd rcl:ocp:mode :RCL:OCP (varExists("selOCP")?(selOCP):1)
#scpiCmd sav:ocp :OCP (varExists("selOCP")?(selOCP):1,(value))

#scpiCmd rcl:opp :RCL:OPP (value)
:setvar: selOPP=inputValue

#scpiCmd rcl:opp:mode :RCL:OPP (varExists("selOPP")?(selOPP):1)
#scpiCmd sav:opp :OPP (varExists("selOPP")?(selOPP):1,(value))

#scpiCmd rcl:list :RCL:LIST (value)
:setvar: selLIST=inputValue

#scpiCmd rcl:list:mode :RCL:LIST (varExists("selLIST")?(selLIST):1)
#scpiCmd sav:list :LIST (varExists("selLIST")?(selLIST):1,(value))

; Initial commands to meter when establishing connection, used to disable local control
; todo: enable, temporarly disabled for testing
#initCmd dev:init

; Final command to meter before breaking connection, used to restore local control
#finalCmd dev:fini

; Used to turn output off for power supplies, generators and electronic loads
#outputOff :INP OFF
; -----------------------------------------------------------------------------
; reading values
; -----------------------------------------------------------------------------
#forceUpperCase 1

; A list of possible column name with unit and formatter (SI, Time, Int, D0..D6) 
; Format: #value ColumnName Unit Format {Selector}
; Selector is only used when column layout varies with mode, this often require the use of #cmdMode
#value Voltage V D4
#value Current A D4
#value Power W D4
#value Capacity Ah D4 Battery BatteryX
#value Time s D4 Battery BatteryX
#askValues voltage?;current?;power?;[mode:Battery,BatteryX]capacity?;[mode:Battery,BatteryX]time?
                                                                            
; Format of answer: f=float, u=remove trailing letters, x=skip, *=Zero upper case values if this value is 0
#askValuesReadFormat uuu[mode:Battery,BatteryX]u[mode:Battery,BatteryX]u

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

; -----------------------------------------------------------------------------
; mode
; -----------------------------------------------------------------------------
; String to ask about actual meter mode, it is mostly used for DMM's
; This is a single line command
#askMode mode?

; 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.
; Number of returned values must match number of columns defined with #value
; This is a single line command

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

; When one of these commands are used through the command interface a new configuration will be done before using #askMode
; Only one word for each #mayModifyMode
; Specify command without initial colon and in the shortest possible form
#mayModifyMode DYN
#mayModifyMode RCL
#mayModifyMode FUNC
#mayModifyMode CURR
#mayModifyMode VOLT
#mayModifyMode POW
#mayModifyMode RES

#cmdMode CC CC
:FUNC CC

#cmdMode CV CV
:FUNC CV

#cmdMode CR CR
:FUNC CR

#cmdMode CW CW
:FUNC CW

#cmdMode Short SHORt
:FUNC SHOR

#cmdMode OPP OPP
rcl:opp:mode

#cmdMode OCP OCP
rcl:ocp:mode

#cmdMode List LIST
rcl:list:mode

#cmdMode Battery BATTERY
rcl:battery:mode

#cmdMode Dynamic_CC DYN_CC
dyn:cc?

#cmdMode Dynamic_CV DYN_CV
dyn:cv?

#cmdMode Dynamic_CR DYN_CR
dyn:cv?

#cmdMode Dynamic_CW DYN_CW
dyn:cw?

;#cmdModeCheck BatteryX BATTERY 0
;:RCL:BATT 1
;:FUNC CC

; -----------------------------------------------------------------------------
; interface
; -----------------------------------------------------------------------------

; This type will specify the handle name for the first device with this type
; This makes it possible to easy get generic handle names for a setup, that will work with a script
#interfaceType Load

; These function will adjust settings
#interface setVoltage :VOLT (value)V

#interface setMaxVoltage :VOLT:UPP (value)V

#interface setCurrent :CURR (value)A

#interface setMaxCurrent :CURR:UPP (value)A

#interface setPower :POW (value)W

#interface setMaxPower :POW:UPP (value)W

#interface setResistance :RES (value)OHM

#interface setMaxResistance :RES:UPP (value)OHM

#interface setRemoteSense :SYST:COMP (value)

#interface setOn :INP (value)

#interface setExtTrigger :SYST:EXIT (value)

#interface setTrigger *TRG

#interface setBatteryTest :RCL:BATT (value)

#interface setOCPTest :RCL:OCP (value)

#interface setOPPTest :RCL:OPP (value)

#interface setDynamicTest :DYN (value)

; These function will return the value applied with the set function
#interface getVoltage :VOLT?
:readformat: u

#interface getMaxVoltage :VOLT:UPP?
:readformat: u

#interface getMinVoltage :VOLT:LOW?
:readformat: u

#interface getCurrent :CURR?
:readformat: u

#interface getMaxCurrent :CURR:UPP?
:readformat: u

#interface getMinCurrent :CURR:LOW?
:readformat: u

#interface getPower :POW?
:readformat: u

#interface getMaxPower :POW:UPP?
:readformat: u

#interface getMinPower :POW:LOW?
:readformat: u

#interface getResistance :RES?
:readformat: u

#interface getMaxResistance :RES:UPP?
:readformat: u

#interface getMinResistance :RES:LOW?
:readformat: u

#interface getRemoteSense :SYST:COMP?
:readmath: listIndex(value,"OFF ON");

#interface getOn :INP?
:readmath: listIndex(value,"OFF ON");

#interface getExtTrigger :SYST:EXIT?
:readmath: listIndex(value,"OFF ON");

#interface getBatteryTest :RCL:BATT?
:string:

#interface getOCPTest :RCL:OCP?
:string:

#interface getOPPTest :RCL:OPP?
:string:

#interface getDynamicTest :DYN?
:string:

; These functions will read the actual values
; These can either contain a number that will reference to a data column or they can contain a command to read the value
#interface readVoltage  0
#interface readCurrent  1
#interface readPower    2
#interface readCapacity 3
#interface readTime     4

; -----------------------------------------------------------------------------
; Setup
; -----------------------------------------------------------------------------

; -----------------------------------------------------------------------------
; CV
; -----------------------------------------------------------------------------
#cmdSetup numberDual ULim CV
:read: :VOLT:LOW?;:VOLT:UPP?
:readformat: uu
:write: voltage:limits #V #V
:tip: Maximum device voltage (<18V for increased precision)
_ DeviceMinVoltage DeviceMinVoltage Low 
V DeviceMinVoltage DeviceMaxVoltage High  

#cmdSetup number U CV
:read: :VOLT?
:readformat: u
:write: :VOLT #V
;:update: Mode
:tip: Load voltage for CV mode
V DeviceMinVoltage DeviceMaxVoltage

#cmdSetup numberDual ILim CC
:read: :CURR:LOW?;:CURR:UPP?
:readformat: uu
:write: current:limits #A #A
:tip: Maximum device current (<3A for increased precision)
_ 0 0 Low 
A 0 DeviceMaxCurrent High 

; -----------------------------------------------------------------------------
; CC
; -----------------------------------------------------------------------------
#cmdSetup number I CC
:read: :CURR?
:readformat: u
:write: :CURR #A
;:update: Mode
:tip: Load current for CC mode
A 0 DeviceMaxCurrent

; -----------------------------------------------------------------------------
; CW
; -----------------------------------------------------------------------------
#cmdSetup numberDual PLim CW
:read: :POW:LOW?;:POW:UPP?
:readformat: uu
:write: power:limits #W #W
:tip: Maximum device power
_ 0 0 Low
W 0 DeviceMaxPower High

#cmdSetup number P CW
:read: :POW?
:readformat: u
:write: :POW #W
;:update: Mode
:tip: Load power for CW mode
W 0 DeviceMaxPower

; -----------------------------------------------------------------------------
; CR
; -----------------------------------------------------------------------------
#cmdSetup numberDual RLim CR
:read: :RES:LOW?;:RES:UPP?
:readformat: uu
:write: resistance:limits #OHM #OHM
:tip: Maximum device resistance
_ DeviceMinResistance DeviceMinResistance Low 
Ω DeviceMinResistance DeviceMaxResistance High

#cmdSetup number R CR
:read: :RES?
:readformat: u
:write: :RES #OHM
;:update: Mode
:tip: Load resistance for CR mode
Ω DeviceMinResistance DeviceMaxResistance

; -----------------------------------------------------------------------------
; Memory
; -----------------------------------------------------------------------------
#cmdSetup buttons LoadM Memory
:write: *RCL #
:update: Mode
M1 1
M2 2
M3 3
M4 4
M5 5

#cmdSetup numberInt Load Memory
:write: *RCL #
:update: Mode
:buttontext: Load
_ 1 99

#cmdSetup buttons SaveM Memory
:write: *SAV #
M1 1
M2 2
M3 3
M4 4
M5 5

#cmdSetup numberInt Save Memory
:write: *SAV #
:buttontext: Save
_ 1 99

; -----------------------------------------------------------------------------
; Dynamic load tests
; -----------------------------------------------------------------------------
#cmdSetup combobox Test Dynamic
; something has to be sent in order to call :update:
:write: #
:update: NoDynamic
CV CV
CC CC
CR CR
CW CW
Pulse Pulse
Toggle Toggle 

#cmdSetup selector NoDynamic Dynamic
Dynamic.Test 
CV Dynamic.CV
CC Dynamic.CC
CR Dynamic.CR
CW Dynamic.CW
Pulse Dynamic.Pulse,Dynamic.Trigger
Toggle Dynamic.Toggle,Dynamic.Trigger

#cmdSetup multi CV Dynamic
:read: dyn:cv?
:readformat: xuuuu
:write: :DYN 1,#V,#V,#HZ,#%;:DYN?
number V1 V 0 DeviceMaxVoltage
number V2 V 0 DeviceMaxVoltage
number Freq Hz 0.001 10000
number Duty % 0 100
:tip: Dynamic CV Test
;:update: Mode

#cmdSetup multi CR Dynamic
:read: dyn:cr?
:readformat: xuuuu
:write: :DYN 3,#OHM,#OHM,#HZ,#%;:DYN?
number R1 Ω 0 DeviceMaxResistance
number R2 Ω 0 DeviceMaxResistance
number Freq Hz 0.001 10000
number Duty % 0 100
:tip: Dynamic CR Test
;:update: Mode

#cmdSetup multi CW Dynamic
:read: dyn:cw?
:readformat: xuuuu
:write: :DYN 4,#W,#W,#HZ,#%;:DYN?
number P1 W 0 DeviceMaxPower
number P2 W 0 DeviceMaxPower
number Freq Hz 0.001 10000
number Duty % 0 100
:tip: Dynamic CW Test
;:update: Mode

#cmdSetup multi CC Dynamic
:read: dyn:cc?
:readformat: xuuuuu
:write: :DYN 2,#A/uS,#A/uS,#A,#A,#HZ,#%;:DYN?
number dI1/dt A/us DeviceMinRate DeviceMaxRate
number dI2/dt A/us DeviceMinRate DeviceMaxRate
number I1 A 0 DeviceMaxCurrent
number I2 A 0 DeviceMaxCurrent
number Freq Hz 0.001 10000
number Duty % 0 100
:tip: Dynamic CC Test
;:update: Mode

#cmdSetup multi Pulse Dynamic
:read: dyn:pulse?
:readformat: xuuuuu
:write: :DYN 5,#A/uS,#A/uS,#A,#A,#S;:DYN?
number dI1/dt A/us DeviceMinRate DeviceMaxRate
number dI2/dt A/us DeviceMinRate DeviceMaxRate
number I1 A 0 DeviceMaxCurrent
number I2 A 0 DeviceMaxCurrent
number Pulse s 0 99999
:tip: Dynamic Pulse Test
;:update: Mode

#cmdSetup multi Toggle Dynamic
:read: dyn:toggle?
:readformat: xuuuu
:write: :DYN 6,#A/uS,#A/uS,#A,#A;:DYN?
number dI1/dt A/us DeviceMinRate DeviceMaxRate
number dI2/dt A/us DeviceMinRate DeviceMaxRate
number I1 A 0 DeviceMaxCurrent
number I2 A 0 DeviceMaxCurrent
:tip: Dynamic Toggle Test
;:update: Mode

#cmdSetup button Trigger Dynamic
:write: *TRG
:tip: Simulate an external trigger command

; -----------------------------------------------------------------------------
; Battery
; -----------------------------------------------------------------------------
#cmdSetup combobox GroupB Battery
:write: rcl:battery #
:update: NoBattery
1 1
2 2
3 3
4 4
5 5
6 6 
7 7
8 8
9 9
10 10

#cmdSetup selector NoBattery Battery
Battery.GroupB 
1 Battery.ValuesB
2 Battery.ValuesB
3 Battery.ValuesB
4 Battery.ValuesB
5 Battery.ValuesB
6 Battery.ValuesB
7 Battery.ValuesB
8 Battery.ValuesB
9 Battery.ValuesB
10 Battery.ValuesB

#cmdSetup multi ValuesB Battery
:read: :RCL:BATT?
:readformat: uuuuu
:write: sav:battery #A,#A,#V,#AH,#M
number Irange A 0 DeviceMaxCurrent
number Idischarge A 0 DeviceMaxCurrent
number Vcutoff V 0 DeviceMaxVoltage
number Capacity Ah 0 99999
number Time Minutes 0 99999
:tip: Battery Discharge Test
;:update: Mode

; -----------------------------------------------------------------------------
; OCP
; -----------------------------------------------------------------------------
#cmdSetup combobox GroupC OCP
:write: rcl:ocp #
:update: NoOCP
1 1
2 2
3 3
4 4
5 5
6 6 
7 7
8 8
9 9
10 10

#cmdSetup selector NoOCP OCP
OCP.GroupC 
1 OCP.ValuesC
2 OCP.ValuesC
3 OCP.ValuesC
4 OCP.ValuesC
5 OCP.ValuesC
6 OCP.ValuesC
7 OCP.ValuesC
8 OCP.ValuesC
9 OCP.ValuesC
10 OCP.ValuesC

#cmdSetup multi ValuesC OCP 
:read: :RCL:OCP?
:readformat: uuuuuuuuuu
:write: sav:ocp #V,#S,#A,#A,#A,#S,#A,#V,#A,#A
number Von V 0 DeviceMaxVoltage
number Von_delay s 0 99
number Irange A 0 DeviceMaxCurrent
number Istart A 0 DeviceMaxCurrent
number Istep A 0 DeviceMaxCurrent
number Istep_delay s 0 99
number Icutoff A 0 DeviceMaxCurrent
number Vocp V 0 DeviceMaxVoltage
number Imax A 0 DeviceMaxCurrent
number Imin A 0 DeviceMaxCurrent
:tip: Over Current Protection Test
;:update: Mode

; -----------------------------------------------------------------------------
; OPP
; -----------------------------------------------------------------------------
#cmdSetup numberInt GroupP OPP
:write: rcl:opp #
:update: NoOPP
_ 1 10

#cmdSetup selector NoOPP OPP
OPP.GroupP 
1 OPP.ValuesP
2 OPP.ValuesP
3 OPP.ValuesP
4 OPP.ValuesP
5 OPP.ValuesP
6 OPP.ValuesP
7 OPP.ValuesP
8 OPP.ValuesP
9 OPP.ValuesP
10 OPP.ValuesP

#cmdSetup multi ValuesP OPP
:read: :RCL:OPP?
:readformat: uuuuuuuuuu
:write: sav:opp #V,#S,#A,#W,#W,#S,#W,#V,#W,#W
number Von V 0 DeviceMaxVoltage
number Von_delay s 0 99
number Irange A 0 DeviceMaxCurrent
number Pstart W 0 DeviceMaxPower
number Pstep W 0 DeviceMaxPower
number Pstep_delay s 0 99
number Pcutoff W 0 DeviceMaxPower
number Vopp V 0 DeviceMaxVoltage
number Pmax W 0 DeviceMaxPower
number Pmin W 0 DeviceMaxPower
:tip: Over Power Protection Test 1
;:update: Mode

; -----------------------------------------------------------------------------
; List
; -----------------------------------------------------------------------------
#cmdSetup combobox GroupL List
:write: rcl:list #
:update: NoList
1 1
2 2
3 3
4 4
5 5
6 6 
7 7

#cmdSetup selector NoList List
List.GroupL 
1 List.ValuesL
2 List.ValuesL
3 List.ValuesL
4 List.ValuesL
5 List.ValuesL
6 List.ValuesL
7 List.ValuesL

#cmdSetup text ValuesL List
:read: :RCL:LIST?
:readmath: replace(value," ","");
:string:
:write: sav:list #
:textwidth: 32
:tip: Imax,Nseq,I1,dI1,T1,I2,dI2,T2,...,In,dIn,Tn,Nloops
;:update: Mode
1000

; -----------------------------------------------------------------------------
; System
; -----------------------------------------------------------------------------
#cmdSetup buttonsOn Sense System
:read: :SYST:COMP?
:write: :SYST:COMP
:string:
:color: (0,0,255)
:tip: Sense voltage from front or rear contacts
Front OFF
Rear ON

#cmdSetup buttonsOn Beep System
:read: :SYST:BEEP?
:write: :SYST:BEEP
:string:
:color: (0,255,255)
:tip: Activate beeper
OFF OFF
ON ON

#cmdSetup buttonsOn Lock System
:read: :SYST:LOCK?
:write: :SYST:LOCK
:string:
:color: (255,255,0)
:tip: Enable/disable device keyboard
OFF OFF
ON ON

#cmdSetup buttonsOn Ext_Trigger System
:read: :SYST:EXIT?
:write: :SYST:EXIT
:string:
:color: (255,0,255)
:tip: External Triggerr for dynamic state, battery test and sequence operation
OFF OFF
ON ON

; -----------------------------------------------------------------------------
; Network
; -----------------------------------------------------------------------------
#cmdSetup text IP_Address Network
:read: :SYST:IPAD?
:write: :SYST:IPAD
15

#cmdSetup text Subnet_mask Network
:read: :SYST:SMASK?
:write: :SYST:SMASK
15

#cmdSetup text Gateway Network
:read: :SYST:GATE?
:write: :SYST:GATE
15

#cmdSetup checkbox Use_DHCP Network
:read: :SYST:DHCP?
:write: :SYST:DHCP
:update: Gateway Subnet_mask IP_Address
:updatedelayed: 2
On 0 1

#cmdSetup numberInt Port Network
:read: :SYST:PORT?
:write: :SYST:PORT
:format: INT
:tip: Default is 18190 and TC is defined for this (18191 cannot be used).
_ 1 65535

#cmdSetup buttons Factory_reset Network
:write: :SYST:FACTRESET
:tip: This will loose the connection and require a reconnect
Reset _

; -----------------------------------------------------------------------------
; Common
; -----------------------------------------------------------------------------
#cmdSetup info Mode
:read: mode?
:updatemodechange:
_

#cmdSetup buttonsOn Output
:read: :INP?
:write: :INP #
:string:
;:update: Mode
:updatealloff:
:tip: Turn output ON or OFF
:color: (0,255,0)
OFF OFF
ON ON



