#%TITLE% DEEPDEVICE.MAC
#
#%NAME%
# DEEPDEVICE.MAC - Macros for operating deep devices though ethernet
# (serial line still to be implemented)
#
#%OVERVIEW%
# These macros simplify scommunication with
# a family of electronic modules that follows certain communication
# conventions defined in the Detyector & Electronics Group and adopted in a
# number of in-house developements at ESRF.
# This kind of modules are called deep devices in the following description.
# %BR%%BR%
# To use these macros, a name (a non-numeric string) must be first
# assigned to each isgdevice with %B%deepdev_add()%B% macro function.%BR%
# Once a isgdevice has been succesfully configured, commands and request can
# be sent to it by means of %B%deepdev_comm()%B% or %B%deep_comm_ack()%B%
# macros.%BR%
# Communication can be flushed by %B%deepdev_flush()%B%.%BR%
# Other macros are %B%deepdevice%B% that shows a list of devices
# currently configured, and %B%deepdebug%B% that toggles a special debug mode.
#
#%EXAMPLE%
# %DL%
# %DT%deepdev_add(\"mydev\", 2, 0, 0)
# %DD%Configures the first device connected IP ... and assigns
# the name \"mydev\" to it.
# %DT%print deepdev_comm(\"mydev\", \"?APPNAME\")
# %DD%Sends the command \"?APPNAME\" to the device and prints the answer
# on the screen.
# %DT%deepdevice
# %DD%Displays a table with the currently configured devices.
# %XDL%
#
#%DEPENDENCIES%
# These macros make use of the following macro sets:
# %UL%
# %LI%stlist.mac
# %XUL%
#%END%
#$Log: deepdevice.mac,v $
#Revision 1.5 2020/02/26 16:17:50 guilloud
#remove definition of toupper/tolower/tocase as the are now built-in (use spec_utils for compatibility)
#
#Revision 1.4 2016/06/01 13:53:12 homsrego
##Since SPEC version 6.03.07 HDW_ERR is a built-in variable and it no longer has to be created at user level to take effect / copied from isgdevice.mac (claustre)
#
#Revision 1.3 2013/12/02 06:42:04 perez
#Allow to pass port device port number to deepdev_scan()
#
#Revision 1.2 2013/11/29 11:45:07 perez
#Small cosmetic improvements
#
#Revision 1.1 2012/03/26 12:05:07 perez
#Add deepdev_setdefault() + fix bug on fresh restart
#
#Revision 1.0 2011/03/18 12:17:45 perez
#Initial revision, used on ID26 March2011
#
#
constant DEEPDEV_OK "\775"
constant DEEPDEV_ERR "\776"
constant DEEPDEV_ERRANSW "\777"
constant DEEPDEV_SCRIPT BLISSADM"/bin/deep"
need spec_utils # for toupper
#%IU%
def deepdev_scan(comdev) '{
local dev_id
local mode answ app prefix ndev indx
prefix = ""
ndev = 0
mode = deepdev__commode(comdev)
if (mode == -1)
return(0)
dev_id = "#" comdev
list_add(DEEP_INT, dev_id)
if (mode == "eth") {
indx = dev_id "_" ndev
if(index(comdev,":") == 0) {
comdev = comdev ":5001"
}
app = deepdev_lowcomm("?APPNAME", mode, comdev, prefix)
if (app == DEEPDEV_ERR)
return(0)
DEEP_DEV[indx]["app"] = app
DEEP_DEV[indx]["addr"] = deepdev_lowcomm("?ADDR", mode, comdev, prefix)
DEEP_DEV[indx]["name"] = deepdev_lowcomm("?DEVNAME", mode, comdev, prefix)
ndev = 1
} else {
print "Not implemented communication mode"
return(0)
}
DEEP_INT[dev_id]["comdev"] = comdev
DEEP_INT[dev_id]["ndev"] = ndev
DEEP_INT[dev_id]["mode"] = mode
DEEP_INT[dev_id]["setup_n"] = SETUP_N
return(ndev)
}'
#%UU%(<name>, <comdev>, <type>, <id>)
#%MDESC%
# Checks for the presence of a deep device. If succesful the device gets
# configured and <name> is internally assigned to it.%BR%
# This macro must be invoked before any other access can be done to the device.
# The communication device <comdev> must be either a number (a serial
# interface in the config file), a string representing a ethernet device
# or an ESRF device name recognised as a Serial Line Device Server.
# %BR%
# The parameters <type> and <id> allow to identify a specific deep device when
# more than one are chained in the same physical communication interface.
# The value of <type> selects the meaning of the identifier <id> as follows:
# %LI%<type>=0: <id> indicates the position of the deep device in the communication chain. The first position is 0.
# %LI%<type>=1: <id> corresponds to the address of the device as returned by the %B%?ADDR%B% command.
# %LI%<type>=2: <id> indicates the name of the device as returned by the %B%?DEVNAME%B% command.
# %LI%<type>=3: <id> indicates the functional type of module as returned by the %B%?APPNAME%B% command.
#
def deepdev_add(name, comdev, type, id) '{
global ESRF_ERR
# Since SPEC version 6.03.07 HDW_ERR is a built-in variable and
# it no longer has to be created at user level to take effect
if (!(whatis("HDW_ERR") & 0x2000000)) {
global HDW_ERR
}
global DEEP_INT[]
global DEEP_DEV[]
global DEEP_CONF[]
global DEEPDEV_ERRMSG
local dev_id ndev i indx prefix mode
list_test DEEP_INT
list_test DEEP_CONF
dev_id = "#" comdev
if ((ndev = DEEP_INT[dev_id]["ndev"]) <= 0 || !SETUP || \
DEEP_INT[dev_id]["setup_n"] != SETUP_N) {
ndev = deepdev_scan(comdev)
}
for (i = 0; i < ndev; i++) {
indx = dev_id "_" i
if (type == 0 && id == i || \
type == 1 && id == DEEP_DEV[indx]["addr"] || \
type == 2 && id == DEEP_DEV[indx]["name"] || \
type == 3 && id == DEEP_DEV[indx]["app"]) {
if((ndev = list_add(DEEP_CONF, name)) <= 0)
break;
DEEP_CONF[name]["index"] = indx
DEEP_CONF[name]["comdev"] = DEEP_INT[dev_id]["comdev"]
DEEP_CONF[name]["pos"] = i
DEEP_CONF[name]["prefix"] = ""
DEEP_CONF[name]["mode"] = DEEP_INT[dev_id]["mode"]
DEEP_CONF[name]["app"] = DEEP_DEV[indx]["app"]
return(ndev);
}
}
return(0)
}'
#%UU%(<name>)
#%MDESC%
# Removes a currently configured deep device from the internal list.
#
def deepdev_remove(name) '{
if (list_check(DEEP_CONF, name) <= 0)
return(-1)
list_remove(DEEP_CONF, name)
if (list_n(DEEP_CONF) <= 0) {
unglobal DEEP_INT DEEP_DEV DEEP_CONF
}
}'
#%UU%(<name>, <type>, <id>)
#%MDESC%
# Checks if <name> is a valid deep device identified by the parameters
# <type> and <id>. Returns -1 if the device is not a registered device, 0
# if it does not match the identification parameters and 1 otherwise.
# The meaning of <type> and <id> is the same that in the
# macro function %B%deepdev_add()%B%.
#
def deepdev_check(name, type, id) '{
local indx
if (list_check(DEEP_CONF, name) <= 0)
return(-1)
indx = DEEP_CONF[name]["index"]
if (type == 0 && id == DEEP_CONF[name]["pos"] || \
type == 1 && id == DEEP_DEV[indx]["addr"] || \
type == 2 && id == DEEP_DEV[indx]["name"] || \
type == 3 && id == DEEP_DEV[indx]["app"]) {
return(1)
} else
return(0)
}'
#%UU%(<name>, <comm>, [<bindata>])
#%MDESC%
# Sends the command <comm> to the device identified by <name> with
# acknowledge request.
# If the command is sent succesfully, this macro function returns the
# constant DEEPDEV_OK.
# If and error happens in the device, DEEPDEV_ERRANSW is returned.%BR%
# If there is a communication error, this macro function returns the
# constant DEEPDEV_ERR.
#
def deepdev_comm_ack(name, comm, bindata) '{
local answ
if (index(comm, "#") != 1) {
comm = "#" comm
}
answ = deepdev_comm(name, comm, bindata)
return(answ)
}'
#%UU%(<name>, <comm>, [<bindata>])
#%MDESC%
# Sends the command <comm> to the device identified by <name>.
# If there is any answer from the device it is returned. If there is no answer
# the macro function returns either DEEPDEV_OK (if the command was sent with no
# error), DEEPDEV_ERR in case of error ot DEEPDEV_ERRANSW.
#
def deepdev_comm(name, comm, bindata) '{
local comdev dev_id prefix mode answer
if (DEEPDEBUG) print "deepdev_comm[" name"]: >" comm "<"
if (!(whatis("DEEP_CONF") & 0x01000000))
return(DEEPDEV_ERR)
if (!(name in DEEP_CONF))
return(DEEPDEV_ERR)
comdev = DEEP_CONF[name]["comdev"]
dev_id = "#" comdev
prefix = DEEP_CONF[name]["prefix"]
mode = DEEP_CONF[name]["mode"]
if (DEEP_INT[dev_id]["flush"]) {
deepdev__flush(mode, comdev, 0)
}
DEEP_INT[dev_id]["flush"] = 1
answer = deepdev_lowcomm(comm, mode, comdev, prefix, bindata)
if (answer != DEEPDEV_ERR) {
DEEP_INT[dev_id]["flush"] = 0
if (answer == DEEPDEV_ERRANSW)
print "ERROR answer from " comdev ": ", DEEPDEV_ERRMSG
else if (DEEPDEBUG) {
local answmsg
answmsg = (answer == DEEPDEV_OK)? "--ok--" : answer
print "deepdev_comm[" name"]: <" answmsg ">"
}
}
return(answer)
}'
#%IU%
def deepdev__flush(mode, comdev, prflag) '{
if (mode == "eth") {
sock_par(comdev, "flush")
# this does not really work, we need something smarter
while(sock_par(comdev, "queue")) {
sock_par(comdev, "flush")
sleep(0.1)
}
}
}'
#%IU%
def deepdev_read_line(mode, comdev) '{
if (mode == "eth") {
answ = sock_get(comdev, 0)
if (!answ)
return(DEEPDEV_ERR)
else {
return(answ)
}
} else {
return(DEEPDEV_ERR)
}
}'
#%IU%
def deepdev__read_array(mode, dev, myarray) '{
if (mode == "eth") {
if (sock_get(dev, myarray) <= 0)
return(DEEPDEV_ERR)
} else
return(DEEPDEV_ERR)
}'
#%IU%
def deepdev__read_binary(mode, comdev, myarray) '{
local answ fstr nchar1 nchar2
long array header[3]
if (deepdev__read_array(mode, comdev, header) == DEEPDEV_ERR) {
print "Error reading binary header"
return(DEEPDEV_ERR)
} else if ((header[0] & 0xffff0000) != 0xa5a50000) {
print "Wrong binary header"
return(DEEPDEV_ERR)
} else {
little_endian = !(header[0] & 0x00000020)
usechksum = !(header[0] & 0x00000010)
units = header[0] & 0x0000000f
size = header[1]
checksum = header[2]
if (!little_endian) {
printf("BIG ENDIAN not supported\n")
return(DEEPDEV_ERR)
} else if (units == 1) {
ubyte array myarray[size]
} else if (units == 2) {
ushort array myarray[size]
} else if (units == 4) {
ulong array myarray[size]
} else if (units == 8) {
double array myarray[size]
} else {
printf("%d bit data types not supported\n", units * 8)
return(DEEPDEV_ERR)
}
if (deepdev__read_array(mode, comdev, myarray) == DEEPDEV_ERR) {
print "Error reading binary data"
return(DEEPDEV_ERR)
}
if (usechksum) {
calcsum = (array_op("sum", myarray) & 0xffffffff)
if (calcsum != checksum) {
printf("Checksum mistmach: calculated=0x%08x vs 0x%08x\n", calcsum, checksum)
return(DEEPDEV_ERR)
}
}
}
return(size * units)
}'
#%IU%
def deepdev__read_ascii(mode, comdev, naked) '{
local answ fstr nchar1 nchar2
local full_answer
answ = deepdev_read_line(mode, comdev)
if (answ == DEEPDEV_ERR) {
print "Communication error with " comdev
return(DEEPDEV_ERR)
} else {
answ = substr(answ, 1, length(answ) - 1)
if (answ == naked) {
return("")
}
fstr = naked " %n ERROR %n"
sscanf(answ, fstr, nchar1, nchar2)
if (nchar1 == 0) {
print "Wrong answer from " comdev
return(DEEPDEV_ERR)
} else if (nchar2 > 0) {
answ = substr(answ, nchar2 + 1)
DEEPDEV_ERRMSG = answ
return(DEEPDEV_ERRANSW)
} else {
answ = substr(answ, nchar1 + 1)
}
}
if (index(answ, "\$")) {
full_answer = ""
while((answ = deepdev_read_line(mode, comdev)) != DEEPDEV_ERR) {
if (index(answ, "\$"))
break
else
full_answer = full_answer answ
}
} else
full_answer = answ
return(full_answer)
}'
#%IU%
def deepdev__read(mode, comdev, naked, bindata) '{
local answ
answ = deepdev__read_ascii(mode, comdev, naked)
if ((answ != DEEPDEV_ERR) && (answ != DEEPDEV_ERRANSW)) {
if ((whatis("bindata") & 0x00ffffff) == 0x00010004) {
if (deepdev__read_binary(mode, comdev, bindata) < 0) {
print "Binary transfer failed"
return(DEEPDEV_ERR)
} else if (DEEPDEBUG)
print "deepdev_bincomm[" comdev "]: binary block read"
}
}
return(answ)
}'
#%IU%
def deepdev__print_binary_header(header) '{
printf ("0x%08x\n", header[0])
printf ("0x%08x\n", header[1])
printf ("0x%08x\n", header[2])
little_endian = !(header[0] & 0x00000020)
usechksum = !(header[0] & 0x00000010)
units = header[0] & 0x0000000f
size = header[1]
checksum = header[2]
print " binary header:"
printf(" byte order: %s ENDIAN\n", little_endian? "LITTLE" : "BIG")
printf(" checksum : %s\n", usechksum? sprintf("YES : 0x%08x", checksum):"NO")
printf(" data type : %d byte%s\n", units, (units > 1)? "s":"")
printf(" size : %d\n", size)
}'
#%IU%
def deepdev__send_binary(mode, comdev, bindata) '{
local checksum flags unit timeout
local typ[]
ulong array header[3]
split(whatis("bindata", "info"), typ)
type = typ[2]
if (type == "ubyte" || type == "byte")
units = 1
else if (type == "ushort" || type == "short")
units = 2
else if (type == "ulong" || type == "long" || type == "float")
units = 4
else if (type == "double")
units = 8
size = array_op("rows", bindata) * array_op("cols", bindata)
flags = 0 # little endian, and checksum
checksum = (array_op("sum", bindata) & 0xffffffff)
header[0] = (0xa5a50000 | flags | units)
header[1] = size
header[2] = checksum
if (DEEPDEBUG) deepdev__print_binary_header(header)
timeout = sock_par(comdev, "timeout")
sock_par(comdev, "timeout", 10)
sock_put(comdev, header)
sock_put(comdev, bindata)
# sock_par(dev, "timeout", timeout)
}'
#%IU%
def deepdev__send_ascii(mode, comdev, comm) '{
comm = comm "\n"
deepdev__flush(mode, comdev, 0)
if (mode == "eth") {
if (sock_put(comdev, comm) < 0)
return(DEEPDEV_ERR)
} else {
print "Wrong communication mode"
return(DEEPDEV_ERR)
}
return(DEEPDEV_OK)
}'
#%IU%
def deepdev__send(mode, comdev, comm, myarray) '{
deepdev__flush(mode, comdev, 0)
if (deepdev__send_ascii(mode, comdev, comm) != DEEPDEV_ERR) {
if ((whatis("myarray") & 0x00ffffff) == 0x00010004) {
if (deepdev__send_binary(mode, comdev, myarray) < 0) {
print "Binary transfer failed"
return(DEEPDEV_ERR)
}
}
return(DEEPDEV_OK)
} else
return(DEEPDEV_ERR)
}'
#%IU%
def deepdev_lowcomm(comm, mode, comdev, prefix, bindata) '{
local firstc
local naked ack query binary
sscanf(comm, " %s ", naked)
firstc = substr(naked, 1, 1)
if (firstc == "#") {
ack = 1
naked = substr(naked, 2)
firstc = substr(naked, 1, 1)
} else
ack = 0
if (firstc == "?") {
query = 1
binary = (substr(naked, 2, 1) == "*")
} else {
query = 0
binary = (firstc == "*")
}
if (binary ) {
if ((whatis("bindata") & 0x00ffffff) != 0x00010004) {
print "deepdevice: needs binary data array"
return(DEEPDEV_ERR)
}
}
naked = toupper(naked)
comm = prefix comm
if (deepdev__send(mode, comdev, comm, (binary && !query)? bindata : 0) == DEEPDEV_ERR)
return(DEEPDEV_ERR)
if (query || ack) {
answ = deepdev__read(mode, comdev, naked, (binary && query)? bindata : 0)
if (!query && answ == "OK")
return(DEEPDEV_OK)
else
return(answ)
} else
return(DEEPDEV_OK)
}'
#%IU%
def deepdev__commode(comdev) '{
local state_str serpar[]
if (comdev + 0 == comdev) {
if (ser_par(comdev, "timeout", 0.5) < 0)
return(-1)
else
return("spec")
} else if (index(comdev, "/") != 0) {
ESRF_ERR = -1
if ((state_str = esrf_io(comdev, "DevStatus")) < 0)
return(-1)
else if (index(state_str, "DEEP")) {
esrf_io(comdev, "DevSetDebug", 0)
return("deepDS")
} else {
serpar[0] = 3; serpar[1] = 256 ; # 1 sec
serpar[2] = 4; serpar[3] = 0 ; # No parity
serpar[4] = 5; serpar[5] = 0 ; # 8 data bits
serpar[6] = 6; serpar[7] = 0 ; # 1 stop bit
serpar[8] = 7; serpar[9] = 9600 ; # baud rate
serpar[10] = 8; serpar[11] = 0xa ; # newline
ESRF_ERR = -1
if (esrf_io(comdev, "DevSerSetParameter", serpar) < 0)
return(-1)
else
return("serialDS")
}
} else {
return("eth")
}
}'
#%UU%(<name>)
#%MDESC%
#
def deepdev_flush(name) '{
local comdev dev_id errcode
comdev = DEEP_CONF[name]["comdev"]
errcode = deepdev__flush(DEEP_CONF[name]["mode"], comdev, DEEPDEBUG)
if (errcode != ISGDEV_OK) {
dev_id = "#" comdev
DEEP_INT[dev_id]["flush"] = 1
}
return(errcode)
}'
#%UU%
#%MDESC%
# Displays a table with the isgdevices currently configured
#
def deepdevice '{
local ndev comdev dev_id
if (whatis("DEEP_CONF") & 0x01000000) {
ndev = list_n(DEEP_CONF)
printf(" # %-9s %-20s %-8s %-8s %s\n", "ID", "Interface", \
"Addr", "Module", "Name")
printf("--- --------- -------------------- -------- -------- -------------------\n")
for (i = 1; i <= ndev; i++) {
name = DEEP_CONF[i]
comdev = DEEP_CONF[name]["comdev"]
dev_id = DEEP_CONF[name]["index"]
printf("%2d %-9s %-20s %-8s %-8s %s\n", i, name, comdev, \
DEEP_DEV[dev_id]["addr"], \
DEEP_DEV[dev_id]["app"], DEEP_DEV[dev_id]["name"])
}
} else {
print "No isgdevices currently configured."
}
}'
#%UU%
#%MDESC%
# Switches debug mode for communication with isgdevices
#
def deepdebug '{
DEBUG ^= 0x40000000
printf("DEEP debug mode is now: %s\n", DEEPDEBUG? "On":"Off")
}'
def DEEPDEBUG '(DEBUG & 0x40000000)'
def deep_getfile(name, remote_file, local_file) '{
local dev command naked
ubyte array dataarray[1]
command = "?*PROG \'" remote_file "\'"
answer = deepdev_comm(name, command, dataarray)
if (answer != DEEP_ERR) {
print answer
print "writting file: " local_file
fmt_write(local_file, "raw", dataarray)
}
return(answer)
}'
#%UU% [hostname]
#%MDESC%
# Launch interactive communication program in a separated xterm.
# Requires the "deep" shell command installed on the current machine.
#
def deep '{
global DEEP_DEFAULT
local cmd
local dev
if(!file_info(DEEPDEV_SCRIPT,"-x")) {
print "ERROR: missing \"deep\" script, hint use blissinstaller"
exit
}
dev = $#?"$1":""
if(!dev && DEEP_DEFAULT) {
dev = DEEP_DEFAULT
}
if(!dev) {
print "Usage: $0 [hostname]"
exit
}
DEEP_DEFAULT = dev
cmd = sprintf("xterm -tn vt100 -e %s %s &",DEEPDEV_SCRIPT,dev)
unix(cmd)
}'
#%IU%(appname, devicename)
#
#
def deepdev_setdefault(appname, argin) '{
local dev
local ndev
local name
local n
local args[]
# check if device name given
n = split(argin,args)
dev = n?args[0]:""
if (!(whatis("DEEP_CONF") & 0x01000000)) {
print "No isgdevices currently configured."
return("")
}
# try to guess device name
if(!dev && (ndev=list_n(DEEP_CONF))>=1) {
if(ndev>1) {
print "ERROR: multi devices not implemented yet, hint: give hostname"
}
i = 1
dev = DEEP_CONF[i]
}
# check if valid device type
if(DEEP_CONF[dev]["app"] != appname) {
print "ERROR: device not of type \""appname"\""
dev = ""
}
# normal end
return(dev)
}'
#%MACROS%
#%AUTHOR% P.Fajardo, (Original 6/10).
# $Revision: 1.5 $ / $Date: 2020/02/26 16:17:50 $
#%TOC%
|