esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]

#%TITLE% syrpump.mac
#%NAME%
# Control of Harvard apparatus Syringe Pump Pico Plus through serial line %BR%
# $Revision: 1.3 $
#%DESCRIPTION%
#%BR% Use %B%syrconfig%B% to configure syringe parameters
#%BR% Use %B%syrshow%B% to display current settings
#%BR% Use %B%syrstart%B%, %B%syrstop%B% to start/stop infuse
#%BR% A counter can be used to get the current accumulated volume infused. 
# At each start command, this volume is reset to zero.
#%BR% To close remote connection and enable keyboard interaction, use %B%syrclose%B%.
#%SETUP%
#%BR% An ESRF device server for serial line has to be used (configuration of
# 2 stop bits), and configured in SPEC as raw:9600. Setup done using macro
# %B%syrsetup%B%
#%END%

#%IU%
def _syrpump_initarr '{
	global SYRPUMP_UNIT[]

	SYRPUMP_UNIT[0]["rate"]= "??/??"
	SYRPUMP_UNIT[0]["cmd"]= ""
	SYRPUMP_UNIT[0]["vol"]= "??"
	SYRPUMP_UNIT[1]["rate"]= "ML/HR"
	SYRPUMP_UNIT[1]["cmd"]= "MLH"
	SYRPUMP_UNIT[1]["vol"]= "ML"
	SYRPUMP_UNIT[2]["rate"]= "ML/MN"
	SYRPUMP_UNIT[2]["cmd"]= "MLM"
	SYRPUMP_UNIT[2]["vol"]= "ML"
	SYRPUMP_UNIT[3]["rate"]= "UL/HR"
	SYRPUMP_UNIT[3]["cmd"]= "ULH"
	SYRPUMP_UNIT[3]["vol"]= "UL"
	SYRPUMP_UNIT[4]["rate"]= "UL/MN"
	SYRPUMP_UNIT[4]["cmd"]= "ULM"
	SYRPUMP_UNIT[4]["vol"]= "UL"
	SYRPUMP_UNIT[5]["rate"]= "NL/HR"
	SYRPUMP_UNIT[5]["cmd"]= "NLH"
	SYRPUMP_UNIT[5]["vol"]= "NL"
	SYRPUMP_UNIT[6]["rate"]= "NL/MN"
	SYRPUMP_UNIT[6]["cmd"]= "NLM"
	SYRPUMP_UNIT[6]["vol"]= "NL"
	SYRPUMP_UNIT[7]["rate"]= "PL/HR"
	SYRPUMP_UNIT[7]["cmd"]= "PLH"
	SYRPUMP_UNIT[7]["vol"]= "PL"
	SYRPUMP_UNIT[8]["rate"]= "PL/MN"
	SYRPUMP_UNIT[8]["cmd"]= "PLM"
	SYRPUMP_UNIT[8]["vol"]= "PL"

	global SYRPUMP_MODEL[]
	SYRPUMP_MODEL[0]["name"]= "Pico Plus"
	SYRPUMP_MODEL[0]["nrate"]= 8
	SYRPUMP_MODEL[1]["name"]= "11 Plus"
	SYRPUMP_MODEL[1]["nrate"]= 4
}'

#%UU% <sernum> <address> <volume_mne> <model_11>
#%MDESC%
# setup of the syringe pump:
# %BR%<sernum> : spec serial line unit. It has to be a device server as we need to configure 2 stop bits
# %BR%<address> : address of the pump as configured on the controller
# %BR%<volume_mne> : counter mnemonic to hold volume infused value
#
def syrsetup '{
	global SYRPUMP[]
	if (($#!=3)&&($#!=4)) {
		eprint "$0 <sernum> <address> <volume_mne> [<model_11>]"
		return
	}
	SYRPUMP["serial"]= int($1)
	SYRPUMP["addr"]= int($2)
	SYRPUMP["mne"]= cnt_num("$3")
	SYRPUMP["model"]= int($4)

	_syrpump_initarr
	_syrpump_initserial
	_syrpump_getpar

	syron
	setup_tail("syr")
}'

#%UU%
#%MDESC%
# Activate volume infused counter on each count
def syron '{
	if (SYRPUMP["mne"]!=-1)
		cdef("user_getcounts", "_syrpump_getcounts;\n", cnt_mne(SYRPUMP["mne"]), 0x02)
	else
		print "SYRPUMP WARNING> Invalid mnemonic for volume counter"
}'

#%UU%
#%MDESC%
# De-activate volume infused counter. resets to 0.
def syroff '{	
	if (SYRPUMP["mne"]!=-1) {
		cdef("", "", cnt_mne(SYRPUMP["mne"]), "delete")
		S[SYRPUMP["mne"]]= 0.
	}
}'

#%IU%
#%MDESC%
# setup cleanup
def syrunsetup '{
	syroff
	unglobal SYRPUMP SYRPUMP_UNIT
}'

#%IU%
def _syrpump_getcounts '{
	S[SYRPUMP["mne"]]= _syrpump_getvolume()
}'

#%IU%
def _syrpump_getvolume() '{
	local ans
	ans= _syrpump_io("VOL", -1, 1)
	if (ans!=-1)
		return (SYRPUMP["way"]*ans)
	else
		return (0.)
}'

#%IU%
def _syrpump_initserial '{
	local dev serarr[]

	dev= ser_par(SYRPUMP["serial"], "device_id")
	esrf_io(dev, "tcp")

    # baudrate
    serarr[0]  = 7
    serarr[1]  = 9600
    # charlength
    serarr[2]  = 5
    serarr[3]  = 0
    # parity
    serarr[4]  = 4
    serarr[5]  = 0
    # stopbits
    serarr[6]  = 6
    serarr[7]  = 2
    # newline
    serarr[8]  = 8
    serarr[9]  = 10
    # timeout
    serarr[10] = 3
    serarr[11] = 64

    esrf_io(dev, "DevSerSetLongParameter", serarr)
	ser_par(SYRPUMP["serial"], "timeout", 0.1)
}'

#%IU%
def _syrpump_io(cmd, inval, outval) '{
	local str ans npar pars[] nb
	if (inval>0)
		ser_put(SYRPUMP["serial"], sprintf("%02d%s%f\r", SYRPUMP["addr"], cmd, inval))
	else
		ser_put(SYRPUMP["serial"], sprintf("%02d%s\r", SYRPUMP["addr"], cmd))

	for (nb=0; nb<10 && (length(str= ser_get(SYRPUMP["serial"]))==0); nb++)
		printf(".")
	for (nb=0; nb<10 && (length(ans= ser_get(SYRPUMP["serial"]))>0); nb++) {
		printf(".")
		str= str ans
	}
	printf("\r")
	npar= split(str, pars, "\r\n")

	# --- check unknown command, out-of-range
	if (index(str, "?")>0) {
		print "SYRPUMP ERROR> Unrecognized command", cmd
		syrflush
		return (-1)
	}
	if (index(str, "OOR")>0) {
		print "SYRPUMP ERROR> Parameter out-of-range", cmd, inval
		syrflush
		return (-1)
	}

	# --- parse address, state
	if (sscanf(pars[npar-1], "%d%[:<>*]c", addr, state)!=2) {
		print "SYRPUMP> Cannot parse reply to", cmd, ":", str
		syrflush
		return (-1)
	}
	if (int(addr)!=SYRPUMP["addr"]) {
		print "SYRPUMP> Oops, wrong reply address"
		syrflush
		return (-1)
	}
	if (state==":")
		SYRPUMP["state"]= "Stopped"
	else if (state==">") {
		SYRPUMP["state"]= "Running forward"
		SYRPUMP["way"]= 1
	}
	else if (state=="<") {
		SYRPUMP["state"]= "Running backward"
		SYRPUMP["way"]= -1
	}
	else if (state=="*")
		SYRPUMP["state"]= "Stalled"

	# --- parse value if needed
	if (outval>0) {
		return (pars[npar-2])
	}
	return (1)
}'

#%IU%
def _syrpump_getpar '{
	local ans ii nrate
	ans= _syrpump_io("DIA", -1, 1)
	if (ans!=-1) SYRPUMP["diameter"]= ans + 0.
	ans= _syrpump_io("RAT", -1, 1)
	if (ans!=-1) SYRPUMP["rate"]= ans + 0.
	ans= _syrpump_io("TAR", -1, 1)
	if (ans!=-1) SYRPUMP["target"]= ans + 0.
	ans= _syrpump_io("RNG", -1, 1)
	SYRPUMP["unit"]= 0
	nrate= SYRPUMP_MODEL[SYRPUMP["model"]]["nrate"]
	for (ii=0; ii<=nrate; ii++) {
		if (ans==SYRPUMP_UNIT[ii]["rate"])
			SYRPUMP["unit"]= ii
	}
}'

#%UU%
#%MDESC%
# Shows current syringe configuration
def syrshow '{
	_syrpump_getpar
	printf("\n< SYRPUMP CONFIG >\n")
	printf("- Diameter : %g MM\n", SYRPUMP["diameter"])
	printf("- Rate     : %g %s\n", SYRPUMP["rate"], SYRPUMP_UNIT[SYRPUMP["unit"]]["rate"])
	printf("\n< SYRPUMP STATUS >\n")
	printf("- Status : %s\n", SYRPUMP["state"])
	printf("- Target : %g %s\n", SYRPUMP["target"], SYRPUMP_UNIT[SYRPUMP["unit"]]["vol"])
	printf("- Current Infused Volume : %g %s\n", _syrpump_getvolume(), SYRPUMP_UNIT[SYRPUMP["unit"]]["vol"])
	printf("\n")
}'

#%UU%
#%MDESC%
# Display current syringwe pump model as cofnigured in syrsetup
def syrmodel '{
	printf("\n< SYRPUMP MODEL > ");
	tty_cntl("md")
	printf("%s", SYRPUMP_MODEL[SYRPUMP["model"]]["name"])
	tty_cntl("me")
	print
}'

#%UU%
#%MDESC%
# Close remote connection to the controller and allow keyboard interaction
def syrclose '{
	_syrpump_io("KEY", -1, 0)
}'

#%UU%
#%MDESC%
# Stops the pump
#
def syrstop '{
	_syrpump_io("STP", -1, 0)
}'

#%UU% <target_volume>
#%MDESC%
# Start the pump up to <target_volume> infused. Units is as set in syrconfig.
#
def syrstart '{
	local tgt
	if ($#!=1) {
		eprint "Usage:  $0 <target_volume>"
		return
	}
	tgt= $1
	# warm if it is already moving
	_syrpump_getpar
	if (SYRPUMP["state"] != "Stopped") {
		tty_cntl("md")
		print "Warning: syringe is already running, please stop it before !!"
		tty_cntl("me")
		exit
	}
	_syrpump_io("CLV", -1, 0)
	if (SYRPUMP["model"]==1)
		_syrpump_io("MLT", fabs(tgt), 0)
	else	_syrpump_io("TGT", fabs(tgt), 0)
	if (tgt*SYRPUMP["way"]<0.)
		_syrpump_io("REV", -1, 0)
	_syrpump_io("RUN", -1, 0)
}'

#%IU%
def syrflush '{
	ser_par(SYRPUMP["serial"], "flush")
}'

#%IU%
def _syrpump_config(diameter, rate, unit) '{
	if (_syrpump_set_unit(unit)) {
		_syrpump_set_diameter(diameter)
		_syrpump_set_rate(rate)
	}
}'

#%UU% [<diameter> <rate> <unit>]
#%MDESC%
# Configure syringe pump parameters:
# %BR%<diameter> : syringe diameter in mm.
# %BR%<rate> : pump flow rate
# %BR%<unit> : rate unit
#
def syrconfig '{
	local diam rate unit ii nrate
	if ($#==3) {
		diam= $1
		rate= $2
		unit= $3
	}
	else {
		diam= getval("- Syringe diameter in mm.", SYRPUMP["diameter"])
		print "- Rate units:"
		nrate= SYRPUMP_MODEL[SYRPUMP["model"]]["nrate"]
		for (ii=1; ii<=nrate; ii++) {
			printf("   %d: %s", ii, SYRPUMP_UNIT[ii]["rate"])
			if (!(ii%4)) printf("\n")
		}
		unit= getval("  Unit used", SYRPUMP_UNIT[SYRPUMP["unit"]]["rate"])
		if (!_syrpump_set_unit(unit)) return
		rate= getval(sprintf("- Flow rate in %s", SYRPUMP_UNIT[SYRPUMP["unit"]]["rate"]), SYRPUMP["rate"])
	}
	_syrpump_config(diam, rate, unit)
}'
	
#%IU%
def _syrpump_set_unit(value) '{
	local ii val nrate
	nrate= SYRPUMP_MODEL[SYRPUMP["model"]]["nrate"]
	if (value!=value+0) {
		for (ii=1; ii<=nrate; ii++)
			if (SYRPUMP_UNIT[ii]["rate"]==value)
				val= ii
	}
	else {
		val= int(value)
	}
	if ((val<1)||(val>nrate)) {
		print "SYRPUMP ERROR> Invalid unit", value
		return (0)
	}
	SYRPUMP["unit"]= val
	return (1)
}'

#%IU%
def _syrpump_set_rate(value) '{
	if (_syrpump_io(SYRPUMP_UNIT[SYRPUMP["unit"]]["cmd"], value, 0)!=-1)
		SYRPUMP["rate"]= value
}'

#%IU%
def _syrpump_set_diameter(value) '{
	if (_syrpump_io("MMD", value, 0)!=-1)
		SYRPUMP["diameter"]= value
}'


#%MACROS%
#%IMACROS%
#%TOC%
#%AUTHOR% E.Papillon