#%NAME%
# Macromotor to control the PACE5000 K0443 Pressure Automated Calibration Equipment
#
#%DESCRIPTION%
#Control of the PACE5000 K0443 Pressure Automated Calibration Equipment.
#%BR% Control with serial line with following resources:
#%BR%- baudrate: 9600
#%BR%- parity: none
#%BR%- charlength: 8
#%BR%- stopbits: 1
#%BR%- timeout: 0xa
#%BR% in spec: serial line in cooked mode
#%BR% Control via etrernet sockets
#%BR% The macromotor controller to be used is 'pace5000'. Each macromotor of
#that type must define a parameter: "serial" with the serial device index or
#"etrernet" with the "address:socket_number" in the config.
#There are two protocols. If nothing specified, ptotocol emulationg older
#Drug instruments will be used. Otherwise in the "ptotocol" parameter should be
#set to "SCPI".
#%END%
global PACE5000_DEBUG PACE5000_SIMUL
global PACE5000_ERR PACE5000
PACE5000_ERR[0]= "ERROR on PACE5000: Command not accepted"
PACE5000_ERR[1]= "ERROR on PACE5000: Secondary address not available"
PACE5000_ERR[2]= "ERROR on PACE5000: Data string not valid"
PACE5000_ERR[3]= "ERROR on PACE5000: Reading in limits"
PACE5000_ERR[4]= "ERROR on PACE5000: Over range (reading exceeds transducer range or 99999"
PACE5000_ERR[5]= "ERROR on PACE5000: end of conversion"
PACE5000_ERR[6]= "ERROR on PACE5000: Valve over temperature"
PACE5000_ERR[7]= "ERROR on PACE5000: checksum error"
#%UU%
#%MDESC% toggle the debug mode
if (!(whatis("__pace5000_debug") & 2)) rdef __pace5000_debug \'#$*\'
def pace5000_debug '{
if ((whatis("__pace5000_debug")>>16) <= 3) { # macro length is 3 bytes: comment
rdef __pace5000_debug "eprint"
print "pace5000 macro debug mode is ON"
PACE5000_DEBUG = 1
}
else {
rdef __pace5000_debug \'#\$*\'
print "pace5000 macro debug mode is OFF"
PACE5000_DEBUG = 0
}
}'
# some programmer help
#%UU%
#%MDESC% toggle debug mode for the present macros.
def pace5000_simul '{
if (PACE5000_SIMUL) { # if present should be true
PACE5000_SIMUL = 0
print "pace5000 simulation is OFF"
} else {
PACE5000_SIMUL = 1
print "pace5000 simulation is ON"
}
}
'
#%IU%
#%MDESC%
# MACRO MOTOR:
# Called by spec after reading the config file
#
def pace5000_config(num,cmd,p1,p2,p3) '{
local dev
__pace5000_debug ">>> pace5000_config: ",num,cmd,p1,p2,p3
# called for each macro-hardware controller
# p1:unit p2: nbchan
if(cmd=="ctrl") {
__pace5000_debug ">>> new controller "
}
# called for each macro motor channel
# p1:unit p2:module p3:channel
if(cmd=="mot") {
PACE5000[num]["protocol"] = 0
#nothing
}
#returns nothing or .error.
}'
#%IU%
#%MDESC%
# MACRO MOTOR:
# Called by spec for setting after reading the config file, after calling _config()
# and only if parameters are set in the config file for a motor.
# Called with motor_par for setting a parameter (if parameter in config file
# or not), and for getting a parameter (if motor NOT in the config file, otherwise
# spec manages it). It manages:
#%BR%- 'serial' or 'ethernet'
#
def pace5000_par(num,key,todo,p1) '{
local mne dev ch
__pace5000_debug ">>> pace5000_par: ",num, key, todo, p1
if (key == "protocol") {
if (todo == "set") {
PACE5000[num]["protocol"] = p1
return
} else {
return PACE5000[num]["protocol"]
}
}
if (key == "serial") {
if (todo == "set") {
PACE5000[num]["dev"] = p1
return
} else {
#note: in principle, todo == get not called here as this parameter
#is in the config file.
__pace5000_debug ">>> pace5000_par: returns ", PACE5000[num]["serial"]
return PACE5000[num]["dev"]
}
}
if (key == "dev") {
if (todo == "set") {
PACE5000[num]["dev"] = p1
return
} else {
return PACE5000[num]["dev"]
}
}
if (key == "type") {
if (todo == "set") {
PACE5000[num]["type"] = p1
return
} else {
return PACE5000[num]["type"]
}
}
}'
#%IU%
#%MDESC% sends to serial line 'serial_number' the string 'cmd'.
#%BR%It automatically ends the command with \\r and \\n
def _pace5000_comm(num, cmd, norep) '{
local splchar aaa
cdef("cleanup_once", sprintf("pace5000_flush %d;",num),"_pace5000")
__pace5000_debug ">>> _pace5000_comm " cmd
if (PACE5000_SIMUL != 1) {
if (PACE5000[num]["type"] == "serial") {
ser_put(PACE5000[num]["dev"], sprintf("%s\r\n", cmd))
if (!norep)
ret = ser_get(PACE5000[num]["dev"], "\r")
} else if (PACE5000[num]["type"] == "ethernet") {
sock_put(PACE5000[num]["dev"], sprintf("%s\r", cmd))
if (!norep)
ret = sock_get(PACE5000[num]["dev"], "\r")
}
}
else {
ret = "0.1"
}
__pace5000_debug ">>> _pace5000_comm returns " ret
nb = split(ret, aaa,PACE5000[num]["split"])
if (nb > 1)
ret = aaa[1]*1
return ret
}'
#%IU%
#%MDESC%
# MACRO MOTOR:
# Called by spec on motor operation. It manages:
#%BR%- position
#%BR%- start_one
#%BR%- get_status
def pace5000_cmd(num,key,p1,p2) '{
local type cmd
__pace5000_debug ">>> pace5000_cmd: ",num, key, p1, p2
if(num == "..") { return }
# get the motor communication tyoe
type = PACE5000[num]["type"]
# return the current pressure
if (key == "position") {
local ret
__pace5000_debug ">>> pace5000_cmd: acting"
if (type) {
cmd = ":SENS:PRES?"
ctrlchar = num
PACE5000[num]["split"] = "PRES"
} else {
# command format: <error reporting>,<notation code>,<current pressure>
# it will respond as: <value(7)><error/status code(3)><terminator>
# if no error, <error/status code(3)> is omitted
cmd = "@1,N1,D0"
ctrlchar = "@"
}
ret = _pace5000_comm(num,cmd)
if (_pace5000_report_error(ret,ctrlchar) == 1) {
__pace5000_debug ">>> pace5000_cmd: --------------- reporting an .ERROR."
return ".error."
} else {
__pace5000_debug ">>> PACE5000(bar): " ret
return ret
}
}
# start a motion. p1: dial abs. pos., p2: dial rel. pos.
if (key == "start_one") {
_pace_setpress(num, p1)
#returns nothing
}
#
# return motor status
#
#0x02: moving
#0: otherwise
#
if (key == "get_status") {
local ret retarr reply
__pace5000_debug ">>> pace5000_cmd: acting"
if (type) {
cmd = ":SENS:PRES?"
ctrlchar = num
PACE5000[num]["split"] = "PRES"
} else {
cmd = "N3"
ctrlchar = "@"
}
reply = _pace5000_comm(dev,cmd)
# it will respond as: <in limit status()><error/status code(3)><terminator>
# if no error, <error/status code(3)> is omitted
if (_pace5000_report_error(reply, ctrlchar) == 1) {
__pace5000_debug ">>> pace5000_cmd: --------------- reporting an .ERROR."
return ".error."
}
if (substr(reply,1,1)=="1") {
__pace5000_debug ">>> pace5000_cmd: status: ", reply , " (not moving)"
return 0
} else if (substr(reply,1,1)=="0"){
__pace5000_debug ">>> pace5000_cmd: status: ", reply , " (moving)"
return 0x02
} else {
__pace5000_debug ">>> pace5000_cmd: unknown status: ", reply
return ".error."
}
}
}'
#%UU% <mnemonic>
#%MDESC% setting as remote the required bender
def pace5000_remote'{
local mirind mynum
mynum = motor_num("$1")
mirind = motor_par(mynum,"serial")
__pace5000_debug ">>>>>> pace5000_remote : motor: " mynum " serial:" mirind
_check_pace5000 "$1"
_pace5000_comm(mirind,"R1")
}'
#%UU% <mnemonic>
#%MDESC% flush the serial line associated to that bender
def pace5000_flush'{
local mirind mynum
mynum = motor_num("$1")
mirind = motor_par(mynum,"serial")
__pace5000_debug ">>>>>> pace5000_flush : motor: " "$1" " serial:" mirind
_check_pace5000 "$1"
ser_par(mirind, "flush", 2)
}'
#%UU% <mnemonic>
#%MDESC% setting as local the required bender
def pace5000_local'{
local mirind mynum
mynum = motor_num("$1")
mirind = motor_par(mynum,"serial")
__pace5000_debug ">>>>>> pace5000_local : motor: " mynum " serial:" mirind
_check_pace5000 "$1"
_pace5000_comm(mirind,"M")
}'
#%IU% <mnemonic>
#%MDESC% check that it is a motor
def _check_pace5000'{
if (motor_num("$1") != -1) {
p "_check_pace5000: to be DEVELOPPED"
}
else {
p "$1" " is not a motor"
exit
}
}'
#%IU% (code, ctrlchar)
#%MDESC% In the case of SCPI protocol: the %B%ctrlchar%B% is the device name.
#A command is sent to the controller's error register to get the error code.
#In the case of the old protocol, the %B%code%B% has the format
#<value>\@<8biterrorcode> and the %B%ctrlchar%B% is "@".
#In the both cases the function returns 0 if no error or 1 if there is an
#error, which is also printed.
def _pace5000_report_error(code, ctrlchar)'{
local myind mycode ii
if (ctrlchar == "@") {
myind = index(code,ctrlchar)
if (myind == 0) {
return(0)
}
mycode = substr(code,myind+1)
for (ii in PACE5000_ERR) {
if ((mycode & 1 << ii) != 0){
p PACE5000_ERR[ii]
}
}
return(1)
} else {
cmd = ":SYST:ERR?"
PACE5000[ctrlchar]["split"] = "ERR"
mycode = _pace5000_comm(ctrlchar,cmd)
if (mycode == 0)
return(0)
return(1)
}
}'
def _pace_setpress(num, val) '{
local cmd dev
dev = PACE5000[num]["dev"]
if (PACE5000[num]["type"]) {
_pace5000_comm(dev,":OUTP 1", 1)
_pace5000_comm(dev, sprintf(":SOUR %f",val))
} else {
# sets <remote mode>,<scale bar>,<P=pressure value>,
# <wait in limit time(sec)>,<controller on>
cmd = sprintf("R1,S0,P=%f,W1,C1",p1)
_pace5000_comm(dev,cmd)
}
}'
def _pace_scpi_error(err) '{
local pace5000_err lerr
if (err == 0)
return(0)
if (err < 0)
err *= -1
else if (err > 0)
err += 200
pace5000_err[102] = "ERROR on PACE5000: Syntax error"
pace5000_err[104] = "ERROR on PACE5000: Data type error"
pace5000_err[108] = "ERROR on PACE5000: Parameter not allowed"
pace5000_err[109] = "ERROR on PACE5000: Missing parameter"
pace5000_err[110] = "ERROR on PACE5000: Command Header Error"
pace5000_err[111] = "ERROR on PACE5000: Header Separator Error"
pace5000_err[112] = "ERROR on PACE5000: Program mnemonic too long"
pace5000_err[113] = "ERROR on PACE5000: Undefined header"
pace5000_err[114] = "ERROR on PACE5000: Header suffix out of range"
pace5000_err[120] = "ERROR on PACE5000: Numeric data error"
pace5000_err[121] = "ERROR on PACE5000: Invalid character in number"
pace5000_err[123] = "ERROR on PACE5000: Exponent too large"
pace5000_err[124] = "ERROR on PACE5000: Too many digits"
pace5000_err[128] = "ERROR on PACE5000: Numeric data not allowed"
pace5000_err[130] = "ERROR on PACE5000: Suffix error"
pace5000_err[131] = "ERROR on PACE5000: Invalid suffix"
pace5000_err[134] = "ERROR on PACE5000: Suffix too long"
pace5000_err[138] = "ERROR on PACE5000: Suffix not allowed"
pace5000_err[140] = "ERROR on PACE5000: Character data error"
pace5000_err[141] = "ERROR on PACE5000: Invalid character data"
pace5000_err[144] = "ERROR on PACE5000: Character data too long"
pace5000_err[148] = "ERROR on PACE5000: Character data not allowed"
pace5000_err[150] = "ERROR on PACE5000: String data error"
pace5000_err[151] = "ERROR on PACE5000: Invalid string data"
pace5000_err[158] = "ERROR on PACE5000: String data not allowed"
pace5000_err[200] = "ERROR on PACE5000: Execution error"
pace5000_err[201] = "ERROR on PACE5000: Invalid while in local"
pace5000_err[202] = "ERROR on PACE5000: Settings lost due to rtl"
pace5000_err[203] = "ERROR on PACE5000: Command protected"
pace5000_err[220] = "ERROR on PACE5000: Parameter error"
pace5000_err[221] = "ERROR on PACE5000: Settings conflict"
pace5000_err[222] = "ERROR on PACE5000: Data out of range"
pace5000_err[223] = "ERROR on PACE5000: Too much data"
pace5000_err[224] = "ERROR on PACE5000: Illegal parameter value"
pace5000_err[240] = "ERROR on PACE5000: Hardware error"
pace5000_err[241] = "ERROR on PACE5000: Hardware missing"
pace5000_err[310] = "ERROR on PACE5000: System error"
pace5000_err[350] = "ERROR on PACE5000: Queue overflow"
pace5000_err[400] = "ERROR on PACE5000: Query error"
pace5000_err[401] = "ERROR on PACE5000: Query only"
pace5000_err[402] = "ERROR on PACE5000: No query allowed"
pace5000_err[403] = "ERROR on PACE5000: Paramerter(s) not expected"
pace5000_err[407] = "ERROR on PACE5000: Emumerated value not in union"
pace5000_err[408] = "ERROR on PACE5000: Illegal number of parameters"
pace5000_err[410] = "ERROR on PACE5000: Run out of memory handle"
pace5000_err[411] = "ERROR on PACE5000: Unit not matched"
pace5000_err[412] = "ERROR on PACE5000: Unit not required"
for (lerr in pace5000_err) {
if (lerr == err)
return(pace5000_err[err])
}
}'
#%MACROS%
#%IMACROS%
#%AUTHOR% mcd january 2011
#%TOC%
#$Revision: 1.3 $
#%END%
#%LOG%
#$Log: pace5000.mac,v $
#Revision 1.3 2013/08/19 12:20:27 beteva
#added socket communication. Some cosmetic changes.
#
#Revision 1.2 2011/07/18 13:08:41 domingue
#inverse polarity for in-limit flag when reading status (with N3)
|