#%NAME% st_falcon.mac
#%TITLE% st_falcon.mac
#$Revision: 1.3 $
#$Log: st_falcon.mac,v $
#Revision 1.3 2007/11/06 15:10:19 witsch
#tested version with appropriate changes for real operation.
#
#Revision 1.1 2007/03/14 13:15:06 witsch
#Initial revision
#
#%DESCRIPTION%
# Macro motors for the ST France pump (>MCAPC)
#%END%
#%SETUP%
# There must be a serial line device server running on the PC with the ST France
#software called Falcon. The Falcon software and the device server must not run
#at the same time! The serial line device server must be set to use 19200 baud,
#7 data bits, 1 stop bit, even parity.
#%SETUP%%B%falcon_scan_user%B% is the local hook macro, that ID27 can modify,
#which will be executed before the counting at each scan point. I will be empty
#at each fresh start, so please save with savmac and use jtdo() to read it from
#the setup.
#%END%
# Modifications history:
#-----------------------------------------------------------
#%IU%(mne)
#%MDESC% Setting a couple of preset values. Device and controller ID.
def mm_falcon_set_serial_parameters(mne) '{
global ESRF_ERR
local params[]
local device
if((device = list_getpar(ST_FALCON, mne, "device")) == -1) {
eprint "ST_FALCON: device undefined."
return(0)
}
# setting the parameters as wished by the Tango DS
params[ 0] = 3 # SL_TIMEOUT /* timeout parameter */
params[ 1] = 500 # timeout value
params[ 2] = 4 # SL_PARITY /* number of parity bits parameter */
params[ 3] = 3 # even parity
params[ 4] = 5 # SL_CHARLENGTH /* number of data bits parameter */
params[ 5] = 1 # 7 data bits
params[ 6] = 6 # SL_STOPBITS /* number of stop bits parameter */
params[ 7] = 0 # 1 stop bit
params[ 8] = 7 # SL_BAUDRATE /* baud rate parameter */
params[ 9] = 19200 # baud
params[10] = 8 # SL_NEWLINE /* new line character parameter */
params[11] = 3 # linefeed
params[12] = 9 # set DTR signal on
params[13] = 1 # yes
ESRF_ERR = -1
esrf_io(device, "DevSerSetParameter", params)
if (ESRF_ERR){
if (FALCON & 128) eprint "ST_FALCON: esrf_io(\"" device "\", \"DevSerSetParameter\", params) failed!"
return(0)
} else {
return(1)
}
}'
#-----------------------------------------------------------
#%IU%(str)
#%MDESC% Don't use this macro directly. Calculates bcc for command to send to
# the controller. simple exclusive or going from the <EOT> to the <ETC>
# character.
def mm_falcon_bcc(str) '{
local bcc, i, char, len
if (FALCON & 128) eprint "mm_falcon_bcc(): string <" str ">"
len = length(str)
if (FALCON & 128) eprint "mm_falcon_bcc(): length:", len
for (i=1; i <= len; i++) {
char = substr(str, i, 1)
bcc = bcc ^ asc(char)
# if (FALCON & 128) {eprint "mm_falcon_bcc(): char", char, asc(char), "bcc:", bcc, sprintf("%c", bcc)}
}
return(bcc)
}' # Ends macro mm_falcon_bcc
#-----------------------------------------------------------
#%IU%(mne, send)
#%MDESC% Don't use this macro directly. Writes a string to the pump.
def mm_falcon_write_aux(mne, send)'{
local len device
if((device = list_getpar(ST_FALCON, mne, "device")) == -1) {
eprint "ST_FALCON: device undefined."
return(0)
}
len = length(send)
if (len > 31) {
eprint "request is too long!"
return(0)
}
ESRF_ERR = -1
esrf_io(device, "DevSerWriteString", send)
if (ESRF_ERR){
if (FALCON & 128) eprint "ST_FALCON: esrf_io(\"" device "\", \"DevSerWriteString\",", send, ") failed!"
return(0)
} else {
return(1)
}
}'
#-----------------------------------------------------------
#%IU%(mne)
#%MDESC% Don't use this macro directly. Reads a string from the pump.
def mm_falcon_read_aux(mne) '{
local device
if((device = list_getpar(ST_FALCON, mne, "device")) == -1) {
if (FALCON & 128) eprint "ST_FALCON: device undefined."
return(0)
}
local x
local ans
# read up to before the BCC
global ESRF_ERR
ESRF_ERR = -1
ans = esrf_io(device, "DevSerReadLine")
if (ESRF_ERR) {
if (FALCON & 128) eprint "ST_FALCON: esrf_io(\"" device "\", \"DevSerReadLine\") failed!"
return(0)
} else {
bcc = esrf_io(device, "DevSerReadNChar", 1)
ans = ans bcc
if (FALCON & 128) {eprint "mm_falcon_read_aux() answer is:", ans}
if (length(ans) < 3) {
return(0)
}
return(ans)
}
}'
#-----------------------------------------------------------
#%IU%(mne)
#%MDESC% Don't use this macro directly. Reads a string from the pump.
def mm_falcon_read_char(mne) '{
local device
if((device = list_getpar(ST_FALCON, mne, "device")) == -1) {
eprint "ST_FALCON: device undefined."
return(0)
}
local ans
global ESRF_ERR
ESRF_ERR = -1
ans = esrf_io(device, "DevSerReadNChar", 1)
ans = asc(ans)
if (ESRF_ERR) {
if (FALCON & 128) eprint "ST_FALCON: esrf_io(\"" device "\", \"DevSerReadNChar\", 1) failed!"
return(0)
} else {
if (FALCON & 128) {eprint "mm_falcon_read_char() answer is:", ans}
return(ans)
}
}'
#-----------------------------------------------------------
#%IU%(mne, cmd)
#%MDESC% Don't use this macro directly. Read a value from the ST France pump.
# It returns the answer of the controller. No BCC is added ! %BR%
# Examples: %BR%
# SW (status word), II (indentification), VO (software version)
def mm_falcon_read_value(mne, cmd) '{
local command answer addr looper
addr = list_getpar(ST_FALCON, mne, "addr")
# I\'m not quite sure how the addressing works, this should however be fine,
# for a low address. One is good!
if (FALCON & 128) {
eprint "mm_falcon_read_value() - writing:", cmd
}
command = sprintf("%c%02x%02x%s%c", 4, 0,((addr<<4) + addr), cmd, 5)
# no bcc created for inquiries!
if (!mm_falcon_write_aux(mne, command)) {
eprint "mm_falcon_read_value() - mm_falcon_write_aux failed!"
return(0)
}
if (!(answer = mm_falcon_read_aux(mne))) {
eprint "mm_falcon_read_value() - mm_falcon_read_aux failed!"
return(0)
}
if (FALCON & 128) {
eprint "mm_falcon_read_value() - reading: \"" answer "\""
}
local char i len bcc bccstr x
# check the answer for correct BCC
# strip received bcc
len = length(answer)
char = substr(answer, len, 1)
bcc = mm_falcon_bcc(substr(answer, 2, len - 2))
if (bcc != asc(char)) {
eprint "mm_falcon_read_value: Bad BCC in answer: \"" answer "\"!"
return(0)
}
# now strip the answer off everything we dont want.
# ie. STX, ETX, BCC and mnemonic
# first char should be STX
if (asc(answer) != 2) {
eprint "mm_falcon_read_value: bad first char."
return(-1)
}
local stripped, x
stripped = substr(answer, 2)
x = index(stripped, "\003") -1
stripped = substr(stripped, 1, x)
if ((x = index(stripped, cmd)) != 1) {
eprint "mm_falcon_read_value: command in answer not in right spot.", x
return(0)
}
stripped = substr(stripped, length(cmd)+1)
return(stripped)
}' # Ends mm_falcon_read_value
#-----------------------------------------------------------
#%IU%(mne, cmd)
#%MDESC% Don't use this macro directly. Set a value on the ST France pump.
# It returns the answer of the controller, if it is anything else than <ACK>.
# The request is passed through the function creating the BCC, here. Sent
# strings mustn\'t be longer than 32 bytes. %BR%
# Examples: %BR%
# 1SP (Consigne de pression), 1RP (Rampe de pression)
def mm_falcon_write_value(mne, cmd) '{
local answer bcc x addr
addr = list_getpar(ST_FALCON, mne, "addr")
if (FALCON & 128) { eprint "mm_falcon_write_value() - writing: <" cmd ">"}
# add one char in front to make bcc start at the right spot
if ((bcc = mm_falcon_bcc(sprintf("%s%c", cmd, 3))) == -1) {
return(0)
}
command = sprintf("%c%02x%02x%c%s%c%c", \
4, 0,((addr<<4) + addr), 2, cmd, 3, bcc)
# if (FALCON & 128) { eprint "mm_falcon_write_value() - string: <" command ">"}
if (!mm_falcon_write_aux(mne, command)) {
eprint "mm_falcon_write_value() - mm_falcon_write_aux failed!"
return(0)
}
answer = mm_falcon_read_char(mne)
if (answer != 6 ) {
eprint "mm_falcon_write_value", command, "NOT acknowledged (" answer ")!"
return(0)
}
if (FALCON & 128) {eprint "mm_falcon_write_value() - reading:", answer == 6 ? "ACK" : "NACK"}
return(1)
}' # Ends macro mm_falcon_write_value
#-----------------------------------------------------------
#%IU%(mne)
#%MDESC% Don't use this macro directly. Use function mm_falcon_read_value() to
#send command "SW" and analyse the answer.
def mm_falcon_get_state(mne) '{
local answer char str
if (!(answer = mm_falcon_read_value(mne, "SW"))) {
eprint "mm_falcon_get_state failed!"
return(0)
}
if (FALCON & 128) {eprint "mm_falcon_get_state(): answer:", answer}
# yields six bytes d1 to d6
# d1 Affichage face avant, 1 - pression, 2 - volume, 3 - temperature, 4 - ana out
# d2 bits d\'alarme: bit0 - alarme basse pression ou 2e alarme haute pression,
# bit 1 - alarme haute pression, bit 2 - alarme haute volume
# d3 face avant: A - avec 1 afficheur, S - sans afficheur, Q - avec 4 afficheurs
# d4 - d6 unused
print "Status word of the ST France Falcon pump"
char = substr(answer, 1, 1)
if (FALCON & 128) {eprint "mm_falcon_get_state() - D1:", char}
str = "Affichage face avant:\n\ten "
if (char == "1") {
str = str "pression"
} else if (char == "2") {
str = str "volume"
} else if (char == "3") {
str = str "temperature"
} else if (char == "4") {
str = str "ana out"
} else {
str = "Strange output from SW command"
}
print str
char = substr(answer, 2, 1)
char = asc(char)
str = "Bits d\'alarme:\n"
if (char & 0x01) {
str = str "alarme basse pression ou 2e alarme haute pression\n"
}
if (char & 0x02) {
str = str "alarme haute pression\n"
}
if (char & 0x04) {
str = str "alarme haute volume\n"
}
print str
char = substr(answer, 3, 1)
str = "Face avant:\n\t"
if (char == "A") {
str = str "avec 1 afficheur"
} else if (char == "S") {
str = str " sans afficheur"
} else if (char == "Q") {
str = str " avec 4 afficheurs"
} else {
str = "Strange output from SW command"
}
print str
}'
#-----------------------------------------------------------
#%IU%(mne)
#%MDESC% Don't use this macro directly. Use function mm_falcon_read_value() to
#send command "II" and analyse the answer.
def mm_falcon_ident(mne) '{
local answer char str Ident
Ident = ">MCAPC"
if (!(answer = mm_falcon_read_value(mne, "II"))) {
eprint "mm_falcon_ident() failed!"
return(0)
}
if (answer != Ident) {
print "mm_falcon_ident(): bad answer from controller"
return(0)
}
return(1)
}'
def mm_falcon_just_spell_out_answer(str) '{
local len, i, char
len = length(str) +1
for (i = 1; i < len; i ++) {
char = substr(str, i, 1)
printf("%3s ", char)
}
print
for (i = 1; i < len; i ++) {
char = substr(str, i, 1)
printf(" %02x ", asc(char))
}
print
}'
#-----------------------------------------------------------
# Macro motor definitions
#-----------------------------------------------------------
#%IU%
#%MDESC%
# Called by spec after reading the config file
def stfalcon_config(motnum, type, unit, module, chan ) '{
local mne
global ST_FALCON
if (motnum != "..") {
mne = motor_mne(motnum)
if (FALCON & 192) {eprint "stfalcon_config(" motnum, ":", type, ":", unit, ":", module, ":", chan }
# serial line device server here please
# The serial line device server should be set in the ADDR field of the
# configuration. It will be available as stfalcon_ADDR in the local scope of
# this function.
list_test ST_FALCON
list_add (ST_FALCON, mne)
list_setpar(ST_FALCON, mne, "device", stfalcon_ADDR)
list_setpar(ST_FALCON, mne, "addr", chan)
# now do some hardware checks
if ( ! mm_falcon_set_serial_parameters(mne) ) {
eprint "Falcon Pump Controller unresponsive, disabled!"
return ".error."
}
if ( ! mm_falcon_ident(mne) ) {
eprint "Falcon Pump Controller is not the right device, disabled!"
return ".error."
}
}
}'
#%IU%
#%MDESC%
# Called by spec
def stfalcon_cmd(num, cmd, p1, p2) ' {
local mne
if (FALCON & 192) eprint "stfalcon_cmd(", num, ":", cmd, ":", p1, ":", p2
if(num == "..") { return }
mne=motor_mne(num)
if ( cmd == "position" ) {
return mm_falcon_read_value(mne, "1PV")
}
if ( cmd == "slew_rate" ) {
local x
x = "1RP" p1 * 16.666
return mm_falcon_write_value(mne, x)
}
if ( cmd == "start_one" ) {
local x
x = "1SP" p1
mm_falcon_write_value(mne, x)
return mm_falcon_write_value(mne, "AXr")
}
if ( cmd == "abort_one" ) {
local x
mm_falcon_write_value(mne, "AXq")
return 1
}
if ( cmd == "get_status" ) {
local x
# first check if its regulating!
x = mm_falcon_read_value(mne, "AX")
# the pump actually sends [rq] plus some spaces.
# reduce check on first char!
if ( asc(x) == 113) return 0 # that means "q"
x = mm_falcon_read_value(mne, "1SP")
x -= mm_falcon_read_value(mne, "1PV")
if (fabs(x) > motor_par(mne, "dc_dead_band")) return 0x02
else return 0
}
} '
#%UU% motor start finish intervals
#%MDESC% Do a scan with the Sanchez Technologies, Falcon Pump controller. Behaves like an ascan.
def falcon_scan '{
local faloop faldel falpts newpts
if ($# != 4) {
eprint "Usage: falcon_scan motor start finish intervals"
exit
}
if((device = list_getpar(ST_FALCON, "$1", "device")) == -1) {
eprint "ST_FALCON: device undefined."
exit
}
_check0 "$1"
#print "$1", _s[0], _f[0], _n1
falpts = int($4) + 1
faldel = ($3 - $2 ) / falpts
_mv $1 $2; _update("$1")
for ( faloop = 1 ; faloop < falpts; faloop ++) {
falcon_scan_user
newpts = $2 + faloop * faldel
_mv $1 newpts; _update("$1")
}
}'
#%UU% macro
#%MDESC% This is the local hook macro, that ID27 can modify, which will be executed before the
# counting at each scan point. I will be empty at each fresh start, so please save with savmac and
# use jtdo() to read it from the setup.
# only defined if not a macro yet.
if (!(whatis("falcon_scan_user") & 2)) rdef falcon_scan_user 'print "falcon_scan_user"'
#%MACROS%
#%IMACROS%
#%AUTHOR% by H. Witsch, BLISS
|