#%TITLE% PEPU.MAC
#
#%NAME%
# Macros to control ESRF PePU device over ethernet
#
#%DESCRIPTION%
#%DL%
#%DT%Configuring counters %DD%
#
# Implements macro counters to read encoder outputs and inputs.
# Implements also the control of embedded acquisition, so called
# streams.
#
# Configure first a macro motor controller with DEVICE field set to
# string "pepu" and ADDR field set to the hostname of PePU device.
# Therefore there must be ONE macro motor controller per PePU.
# The "NUM" field must be set to 9%BR%
#
# Then configure a counter using the previous controller, the "channel"
# is used to select the output channel (from 1 to 8)%BR%
#
# An optional parameter "type" can be set to select what to read
# on the given channel ("IN", "OUT", "AUX"). By default, the input
# will be read%BR%
#
#%DT%Configuring motors %DD%
#
# Macro motors can be configured to control the encoder outputs.
#
# Configure first a macro motor controller with DEVICE field set to
# string "pepu" and ADDR field set to the hostname of PePU device.
# Therefore there must be ONE macro motor controller per PePU.
# The "NUM" fielt must be set to 9%BR%
#
# Then configure a motor using the previous controller, the "channel"
# is used to select the output channel (from 5 to 8)%BR%
# An optional parameter "type" can be set to select what to read
# on the given channel ("IN", "OUT", "AUX"). By default, the output
# will be read%BR%
#
#%XDL%
#
#%END%
#
#%UU% hostname
#%MDESC%
# Launch an interactive command line interface.
# This allows for intance to check/setup the instrument configuration
# using direct command like ?HELHP
#
def pepu '{
local cmd
local pyc
if($# != 1) {
print "Usage: $0 hostname"
exit
}
pyc = "pepuconsole.py"
p sprintf("%s/bin/%s", BLISSADM, pyc)
if(!file_info(sprintf("%s/bin/%s", BLISSADM, pyc), "-x")) {
printf("Missing \"%s\" script, hint use blissinstaller\n", pyc)
exit
}
cmd = sprintf("%s %s", pyc, "$1")
unix(cmd)
}'
#%IU%()
#%MDESC%
# Called by spec after reading the config file
#
def pepu_config(num, type, p1, p2, p3) '{
#
# p1==controller index p2==number of motors supported
#
if(type == "ctrl") {
local dev
local ans
# get hostname from config
dev = pepu_ADDR
# minimum check on controller
ans = pepu_comm(dev, "?APPNAME")
if(!index(ans, "PEPU")) {
_pepu_err
printf("not a PePU instrument: \"%s\"\n", dev)
return ".error."
}
ans = pepu_comm(dev, "?VERSION")
printf("Using \"%s\" for PePU instrument (version %s)\n", dev, ans)
# normale end
return
}
#
# p1==unit p2==0 p3==channel
#
if(type == "cnt") {
local typ
# check type parameter
typ = counter_par(num, "type")
if(typ == 0) {
# by default, read encoder inputs
counter_par(num, "type", "IN", "add")
}
#TODO: add checks on type string
# needed to distinguish counters from motors
counter_par(num, "pepu_type", "counter", "add")
# normale end
return
}
#
# p1==unit p2==0 p3==channel
#
if(type == "mot") {
local typ
# check type parameter
typ = motor_par(num, "type")
if(typ == 0) {
# by default, read encoder inputs
motor_par(num, "type", "OUT", "add")
}
#TODO: add checks on type string
# needed to distinguish counters from motors
motor_par(num, "pepu_type", "motor", "add")
# normale end
return
}
}'
#%IU%()
#%MDESC%
# Called by spec on motor or counter operations
#
def pepu_cmd(num, key, p1, p2) '{
local mne
local dev
local cha
local typ
local cmd ans val
#
# Handle actions at controller level
#
if(num == "..") {
return
}
#
# Handle actions at counter level
#
if (key == "counts") {
dev = counter_par(num, "address")
cha = counter_par(num, "channel")
typ = counter_par(num, "type")
cmd = sprintf("?CHVAL %s%d", typ, cha)
ans = pepu_comm(dev, cmd)
if(sscanf(ans, "%lf", val) != 1) {
_pepu_err
print "unable to parse channel value"
return ".error."
}
return val
}
# get rid of any other counter requests
if(counter_par(num, "pepu_type") == "counter") {
return
}
#
# Handle actions at motor level
#
mne = motor_mne(num)
dev = motor_par(num, "address")
cha = motor_par(num, "channel")
typ = motor_par(num, "type")
#
# return the current motor position in mm or deg
#
if (key == "position") {
cmd = sprintf("?CHVAL %s%d", typ, cha)
ans = pepu_comm(dev, cmd)
if(sscanf(ans, "%lf", val) != 1) {
_pepu_err
print "unable to parse channel value"
return ".error."
}
return val
}
#
# start a motion (p1==abs pos, p2==rel pos, with pos in mm or deg)
#
if (key == "start_one") {
cmd = sprintf("CHVAL %s%d %g", typ, cha, p1)
pepu_comm(dev, cmd)
return
}
#
# called on set_dial (p1==abs pos in mm or deg)
#
if (key == "set_position") {
cmd = sprintf("CHSET %s%d %g", typ, cha, p1)
pepu_comm(dev, cmd)
return
}
}'
#%IU%(hostname, command)
#%MDESC%
# Send a command to the given PePU device and returns the answer if any
# TODO: port to deepdevice.mac
#
def pepu_comm(hn, cmd) '{
local ans
local ln lc
local n args
_dance_debug(sprintf("WR: \"%s\"", cmd))
dev = sprintf("%s%s", hn, index(hn,":")?"":":5000")
pepu_wr(dev, cmd)
if(index(cmd, "?") || index(cmd, "#")) {
ans = pepu_rd(dev)
} else {
ans = ""
}
# remove terminator character and useless blanks
ln = length(ans)
if(ln) {
string array str_a[ln]
str_a = ans
for(ln--;ln>=0;ln--) {
lc = str_a[ln]
if((lc!=0x0a) && (lc!=0x0d) && (lc!=0x20))
break
}
ans = substr(ans, 0, ln+1)
}
_dance_debug(sprintf("RD: \"%s\"", ans))
# bad answer from device
n = split(ans, args)
if(n < 1) {
# TODO: print out error?
return ans
}
# TODO: handle error returned by device
# remove command echoed by device
return substr(ans, index(ans, " ")+1)
}'
#%IU%(device, command)
#%MDESC%
# Send a command to the given PePU device
# TODO: port to deepdevice.mac
#
def pepu_wr(dev, cmd) '{
cmd = cmd "\n"
sock_par(dev, "flush")
sock_put(dev, cmd)
}'
#%IU%(device)
#%MDESC%
# Waits for an answer from the given PePU device and returns it
# TODO: port to deepdevice.mac
#
def pepu_rd(dev) '{
local ret
local ans
local mline
sock_par(dev, "timeout", 2)
for(mline=0, ret="";;) {
ans = sock_get(dev, "\n")
if(_pepu_lastchar(ans) == "\$")
mline = (mline == 0)
ret = ret ans
if(mline == 0)
break
}
return(ret)
}'
#%IU%
#%MDESC%
# Return the last significant character (non terminator)
#
def _pepu_lastchar(ans) '{
local lc
local ln
if((ln = length(ans)) == 0) {
return("")
}
string array str_a[ln]
str_a = ans
for(ln--;ln>=0;ln--) {
lc = str_a[ln]
if((lc!=0x0a) && (lc!=0x0d) && (lc!=0x20)) {
break
}
}
return(substr(ans, ln+1, 1))
}'
#%IU%
#%MDESC%
# Pure cosmetic macro
#
def _pepu_err '{
tty_cntl("md")
printf("PEPU ERROR: ")
tty_cntl("me")
}'
#%IU%(src_arrname, dst_arrname)
#%MDESC%
# Convert the given byte array to double array assuming
# PePU SFIXED data (40bits mantise + 8bits frac) is encoded over 64bits.
# The destination array is created with the given name.
# Retunrs the number of doubles converted or -1 in case of error.
#
def _pepu_sfixed_40_8_to_double(src_arrname, dst_arrname) '{
local sz_b sz_f
local sz_u
local i j val
# data is given over 64bits values (==8bytes)
sz_u = 8
# TODO: check array type
# TODO: support any type of integer array, remapping to byte array
# check number of data
sz_b = array_op("cols", @src_arrname)
if(sz_b % sz_u) {
_pepu_err
print "wrong array size"
return -1
}
sz_f = sz_b / sz_u
double array @dst_arrname[sz_f]
for(i=0;i<sz_f;i++) {
for(j=0, val=0.0;j<sz_u;j++) {
val += (@src_arrname[(i*sz_u)+j])<<(j*8)
}
#if(val > ((1<<47)-1)) {
if(@src_arrname[(i*sz_u)+5] & 0x80) {
val = val - (1<<48)
}
val /= 256.0
@dst_arrname[i] = val
}
return sz_f
}'
#
# ---------------------------- data streams -------------------------------
# TODO: move this to deepdevice.mac
# if streams implemented generic in DANCE
#
#%UU% logical_name host_name
#%MDESC%
# Create a new logical name to acces the PePU instrument given
# by its name on the network.
#
def pepu_setup '{
global PEPU[]
# retrieve the PEPU instrument hostname
if ($# != 2) {
print "Usage: $0 <logical_name> <host_name>"
exit
}
if(_pepu_setup("$1", "$2")) {
exit
}
printf("Using \"%s\" as PePU instrument (version %s)\n", \
PEPU["$1"]["device"], PEPU["$1"]["version"])
}'
#%IU%(logical_name, hostname)
#%MDESC%
# If the logical name already exists, it will be overwritten.
# Returns non null in case of error.
#
def _pepu_setup(name, dev) '{
global PEPU[]
local cmd ans
# minimum check on controller
ans = pepu_comm(dev, "?APPNAME")
if(!index(ans, "PEPU")) {
_pepu_err
printf("not a PePU instrument: \"%s\"\n", dev)
return(-1)
}
ans = pepu_comm(dev, "?VERSION")
# remove any previous configuration
list_remove(PEPU, name)
# new logical device
list_add(PEPU, name)
PEPU[name]["device"] = dev
PEPU[name]["version"] = ans
return(0)
}'
#%UU% logical_name stream_name
#%MDESC%
# Create a new stream, identified by its name, on a PePU instrument.
#
def pepu_stream_add '{
global PEPU[]
# retrieve the PEPU instrument hostname
if ($# != 2) {
print "Usage: $0 <logical_name> <stream_name>"
exit
}
if(_pepu_stream_add("$1", "$2")) {
exit
}
printf("Stream \"%s\": created on instrument \"%s\"\n", \
"$2", PEPU["$1"]["device"])
}'
#%IU%(logical_name, stream_name)
#%MDESC%
#
def _pepu_stream_add(name, sid) '{
global PEPU[]
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU, name) == -1) {
_pepu_err
printf("wrong PePU logical name: \"%s\"\n", name)
return(-1)
}
dev = PEPU[name]["device"]
# remove any previous configuration
_pepu_stream_del(sid)
# create an empty dstream
ans = pepu_comm(dev, sprintf("#DSTREAM %s GLOBAL", sid))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to create stream: \"%s\"\n", sid)
printf("\"%s\"\n", ans)
return(-1)
}
# by default the stream is ON at creation
pepu_comm(dev, sprintf("DSTREAM %s OFF", sid))
# at this point we have a valid dstream
list_add(PEPU_STREAMS, sid)
PEPU_STREAMS[sid]["device"] = dev
PEPU_STREAMS[sid]["pepu"] = name
PEPU_STREAMS[sid]["sources"] = ""
return(0)
}'
#%UU% stream_name
#%MDESC%
# Remove any previous configuration for the given stream.
# The corresponding instrument will also be updated.
#
def pepu_stream_del '{
global PEPU[]
# retrieve stream name
if ($# != 1) {
print "Usage: $0 <stream_name>"
exit
}
if(_pepu_stream_del("$1")) {
exit
}
printf("Stream \"%s\": deleted\n", "$1")
}'
#%IU%(stream_name)
#%MDESC%
# No error returned.
#
def _pepu_stream_del(sid) '{
global PEPU[]
global PEPU_STREAMS[]
local dev
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
# no need to print error, just do nothing
return(0)
}
dev = PEPU_STREAMS[sid]["device"]
pepu_comm(dev, sprintf("DSTREAM %s DEL GLOBAL", sid))
list_remove(PEPU_STREAMS, sid)
return(0)
}'
#%UU% stream_name start clock
#%MDESC%
# Configure the signal used to start the acquistion and
# the signal used as acquistion clock.
# The signals could be "SOFT" "DI1" "DI2" "FREQ"
#
def pepu_stream_trig '{
# minimum checks
if ($# != 3) {
print "Usage: $0 <stream_name> <start_signal> <clock_signal>"
exit
}
if(_pepu_stream_trig("$1", "$2", "$3")) {
exit
}
printf("Stream \"%s\": start:\"%s\" clock:\"%s\"\n", "$1", "$2", "$3")
}'
#%IU%(stream_name, start, clock)
#%MDESC%
#
def _pepu_stream_trig(sid, start, clock) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
# check signal names
local sig_s sig_c sig_a
sig_a = "DI1 DI2 SOFT FREQ"
sig_s = _dance_toupper(start)
if(!index(sig_a, sig_s)) {
_pepu_err
printf("invalid start signal: \"%s\"\n", start)
return(-1)
}
sig_c = _dance_toupper(clock)
if(!index(sig_a, sig_c)) {
_pepu_err
printf("invalid clock signal: \"%s\"\n", clock)
return(-1)
}
# update stream configuration
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s TRIG %s %s", sid, sig_s, sig_c))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to configure the acquisition triggering\n")
printf("\"%s\"\n", ans)
return(-1)
}
PEPU_STREAMS[sid]["start"] = sig_s
PEPU_STREAMS[sid]["clock"] = sig_c
return(0)
}'
#%UU% stream_name hz
#%MDESC%
# Configure the acquisition clock, given in Hz.
# Useless if clock will be an external signal.
#
def pepu_stream_fsample '{
# minimum checks
if ($# != 2) {
print "Usage: $0 <stream_name> <hz>"
exit
}
if(_pepu_stream_fsample("$1", $2)) {
exit
}
printf("Stream \"%s\": acquisition clock:%dHz\n", "$1", int($2))
}'
#%IU%(stream_name, hz)
#%MDESC%
#
def _pepu_stream_fsample(sid, hz) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
# minimum checks
if((hz < 1) || (hz>10e6)) {
_pepu_err
printf("invalid frequency\n")
return(-1)
}
hz = int(hz)
# update stream configuration
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s FSAMPL %dHz", sid, hz))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to configure the acquisition clock\n")
printf("\"%s\"\n", ans)
return(-1)
}
PEPU_STREAMS[sid]["fsample"] = hz
return(0)
}'
#%UU% stream_name nsamples
#%MDESC%
# Configure the number of samples
#
def pepu_stream_nsample '{
# minimum checks
if ($# != 2) {
print "Usage: $0 <stream_name> <nsamples>"
exit
}
if(_pepu_stream_nsample("$1", $2)) {
exit
}
printf("Stream \"%s\": number of samples:%d\n", "$1", int($2))
}'
#%IU%(stream_name, nsample)
#%MDESC%
#
def _pepu_stream_nsample(sid, nsample) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
# minimum checks
if(nsample < 1) {
_pepu_err
printf("invalid number of samples\n")
return(-1)
}
nsample = int(nsample)
# update stream configuration
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s NSAMPL %d", sid, nsample))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to configure the number of samples\n")
printf("\"%s\"\n", ans)
return(-1)
}
PEPU_STREAMS[sid]["nsample"] = nsample
return(0)
}'
#%IU%(stream_name, nsample_limit)
#%MDESC%
#
def _pepu_stream_nsample_limit(sid, n_limit) '{
global PEPU_STREAMS[]
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
PEPU_STREAMS[sid]["n_limit"] = n_limit
return(0)
}'
#%UU% stream_name channels
#%MDESC%
# The given channel will be acquired.
#
def pepu_stream_source_add '{
# minimum checks
if ($# != 2) {
print "Usage: $0 <stream_name> <channel>"
exit
}
if(_pepu_stream_source_add("$1", "$2")) {
exit
}
printf("Stream \"%s\": channel added:\"%s\"\n", "$1", "$2")
}'
#%IU%(stream_name, channel)
#%MDESC%
# Allowed channels "IN1/6" "CALC1/8"
def _pepu_stream_source_add(sid, chname) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
# check channel name
local n ch
ch = _dance_toupper(chname)
if(index(ch, "IN") == 1) {
n = int(substr(chname, 3, 1))
if((n<1) || (n>6)) {
_pepu_err
printf("invalid channel name number: \"%s\"\n", chname)
return(-1)
}
} else if(index(ch, "CALC") == 1) {
n = int(substr(chname, 5, 1))
if((n<1) || (n>8)) {
_pepu_err
printf("invalid calc channel number: \"%s\"\n", chname)
return(-1)
}
} else {
_pepu_err
printf("invalid channel name: \"%s\"\n", chname)
return(-1)
}
# check if channel already configured
local src
src = PEPU_STREAMS[sid]["sources"]
if(index(src, ch)) {
return(0)
}
# update stream configuration
src = _dance_trim(sprintf("%s %s", src, ch))
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s SRC %s", sid, src))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to add channel: \"%s\"\n", chname)
printf("\"%s\"\n", ans)
return(-1)
}
PEPU_STREAMS[sid]["sources"] = src
return(0)
}'
#%IU%(stream_name)
#%MDESC%
# Returns the current number of sources
#
def _pepu_stream_nsources(sid) '{
local tt[]
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
return(split(PEPU_STREAMS[sid]["sources"], tt))
}'
#%IU%(stream_name)
#%MDESC%
# Returns the current data array name
#
def _pepu_stream_arrname(sid) '{
local tt[]
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
return PEPU_STREAMS[sid]["arr"]
}'
#%UU% stream_name
#%MDESC%
# Switch on the given stream and launch the acquistion.
# Handle also the software start if configured.
#
def pepu_stream_start '{
# minimum checks
if ($# != 1) {
print "Usage: $0 <stream_name>"
exit
}
if(_pepu_stream_start("$1")) {
exit
}
printf("Stream \"%s\": acquisition launched\n", "$1")
}'
#%IU%(stream_name)
#%MDESC%
#
def _pepu_stream_start(sid) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s APPLY", sid))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to apply configuration\n")
printf("\"%s\"\n", ans)
return(-1)
}
if(0) {
ans = pepu_comm(dev, sprintf("#DSTREAM %s FLUSH", sid))
ans = pepu_comm(dev, sprintf("#DSTREAM %s ON", sid))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to launch acquisition\n")
printf("\"%s\"\n", ans)
return(-1)
}
}
# create the array that will store data
local bidon[] nch nsample arrname
nch = split(PEPU_STREAMS[sid]["sources"], bidon)
arrname = sprintf("pepu_%s_data", sid)
nsample = PEPU_STREAMS[sid]["nsample"]
double array @arrname[nsample][nch]
PEPU_STREAMS[sid]["arr"] = arrname
# handle the software start of acquistion
local start
start = list_getpar(PEPU_STREAMS, sid, "start")
if((start == -1) || (start != "SOFT")) {
return(0)
}
ans = pepu_comm(dev, "#STRIG")
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to handle the software satrt of acquisition\n")
printf("\"%s\"\n", ans)
return(-1)
}
return(0)
}'
#%UU% stream_name
#%MDESC%
# Switch off the given stream and stop the acquistion.
#
def pepu_stream_stop '{
# minimum checks
if ($# != 1) {
print "Usage: $0 <stream_name>"
exit
}
if(_pepu_stream_stop("$1")) {
exit
}
printf("Stream \"%s\": acquisition stopped\n", "$1")
}'
#%IU%(stream_name)
#%MDESC%
#
def _pepu_stream_stop(sid) '{
global PEPU_STREAMS[]
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("#DSTREAM %s STOP", sid))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to stop acquisition\n")
printf("\"%s\"\n", ans)
return(-1)
}
ans = pepu_comm(dev, sprintf("#DSTREAM %s OFF", sid))
if(index(ans, "ERROR")) {
_pepu_err
printf("unable to switch off the stream\n")
printf("\"%s\"\n", ans)
return(-1)
}
return(0)
}'
#%IU%(stream_name)
#%MDESC%
# Returns the number of samples ready to be read
#
def _pepu_stream_nsample_cur(sid) '{
local dev cmd ans
local n n_cur
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("?DSTREAM %s NSAMPL", sid))
n = sscanf(ans, "%d", n_cur)
return(n_cur)
}'
#%IU%(stream_name, nsamples, arrname)
#%MDESC%
# Read the given number of samples and stores them in a array.
# The array will be created and named as given.
# It will be of type double
#
def _pepu_stream_read(sid, n_cur, subarrname) '{
local dev cmd ans
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
dev = PEPU_STREAMS[sid]["device"]
# get raw data from PEPU
cmd = sprintf("?*DSTREAM %s READ %d", sid, n_cur)
_dance_get_array(dev, cmd, "ldat")
# convert to float value data
_pepu_sfixed_40_8_to_double("ldat", subarrname)
}'
#%IU%(stream_name)
#%MDESC%
#
def _pepu_stream_poll_read(sid) '{
global PEPU_STREAMS[]
local dev cmd ans
local n n_cur n_tot nsample
local arrname
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
return(-1)
}
# TODO: add tests if acquisition has been launched
dev = PEPU_STREAMS[sid]["device"]
arrname = PEPU_STREAMS[sid]["arr"]
nsample = PEPU_STREAMS[sid]["nsample"]
#TODO: handle timeout
for(n_tot=0;n_tot<nsample;) {
#ans = pepu_comm(dev, sprintf("?DSTREAM %s NSAMPL", sid))
#n = sscanf(ans, "%d", n_cur)
n_cur = _pepu_stream_nsample_cur(sid)
if(n_cur == 0) {
# TODO: add timeout here
sleep(.01)
continue
}
# NOTE MP 21thNov: bug in binary transfer commands (any binary request)
# with large (well, not so large) data. Bug to be fixed
# by FLM. Meantime, limit transfer size.
if((n_bug = PEPU_STREAMS[sid]["n_limit"]) != 0) {
n_cur = (n_cur>n_bug)?n_bug:n_cur
}
# get raw data from PEPU
#cmd = sprintf("?*DSTREAM %s READ %d", sid, n_cur)
#_dance_get_array(dev, cmd, "ldat")
# convert to value data
#_pepu_sfixed_40_8_to_double("ldat", "fdat")
_pepu_stream_read(sid, n_cur, "fdat")
# resort data in columns and
# store partial data in global full data
array_copy(@arrname[n_tot:(n_tot+n_cur-1)][], fdat)
n_tot += n_cur
}
}'
#%UU% stream_name
#%MDESC%
# Print out current stream configuration
#
def pepu_stream '{
global PEPU_STREAMS[]
local dev cmd ans
local sid
local n_bug
# minimum checks
if ($# != 1) {
print "Usage: $0 <stream_name>"
exit
}
sid = "$1"
# minimum checks
if(list_item(PEPU_STREAMS, sid) == -1) {
_pepu_err
printf("non configured stream: \"%s\"\n", sid)
exit
}
local start clock nsample fsample sources arrname
start = list_getpar(PEPU_STREAMS, sid, "start")
clock = list_getpar(PEPU_STREAMS, sid, "clock")
nsample = list_getpar(PEPU_STREAMS, sid, "nsample")
fsample = list_getpar(PEPU_STREAMS, sid, "fsample")
sources = list_getpar(PEPU_STREAMS, sid, "sources")
arrname = list_getpar(PEPU_STREAMS, sid, "arr")
printf("Stream \"%s\":\n", sid)
printf("\tStart : %s\n", (start !=-1)?start:"????")
printf("\tClock : %s\n", (clock !=-1)?clock:"????")
printf("\tNsample: %s\n", (nsample!=-1)?nsample:"????")
printf("\tFsample: %sHz\n", (fsample!=-1)?fsample:"????")
printf("\tSources: \"%s\"\n", (sources!=-1)?sources:"????")
printf("\tArray : %s[][]\n", (arrname!=-1)?arrname:"????")
#TODO: check that conf in globals matches the conf in the instrument
dev = PEPU_STREAMS[sid]["device"]
ans = pepu_comm(dev, sprintf("?DSTREAM %s", sid))
}'
#
# ----------------------- binary transfers toolkit -------------------------
# TODO: move this to deepdevice.mac
#
#%IU%(hostname, query_cmd, array_name)
#%MDESC%
# Returns the number of data read or -1 in case of error.
#
def _dance_get_array(hn, cmd, arrname) '{
local ulong array header[3]
local dev
local no_checksum checksum bin_checksum
local data_sz data_n n
# check argin validity
if(substr(cmd, 1, 2) != "?*") {
_pepu_err
printf("not a binary query command: \"%s\"\n", cmd)
return -1
}
# full socket name
dev = sprintf("%s%s", hn, index(hn,":")?"":":5000")
# TODO: whats the data type in DANCE??
#} else if(!index(whatis("arr", "info"), "ushort")) {
# _pepu_err
# printf("bad binary data array\n")
# return -1
#}
# get the ASCII part of the answer
# TODO: check error
ans = pepu_comm(dev, cmd)
if(index(ans, "ERROR")) {
_pepu_err
printf("can not get data: \"%s\"\n", ans)
return -1
}
# now comes the binary part of the answer
sock_get(dev, header)
_dance_debug(sprintf("hearder : 0x%08x", header[0]))
_dance_debug(sprintf("size : 0x%08x", header[1]))
_dance_debug(sprintf("checksum: 0x%08x", header[2]))
# mimimum check on magic number
if(((header[0]&0xffff0000)>>16) != 0xa5a5) {
_pepu_err
printf("not a DANCE/PEPU binary format, giving up\n")
sock_par(dev, "flush")
return -1
}
# check if checksum has to be handled or not
no_checksum = (header[0]&0x00000010)
checksum = header[2]
_dance_debug(sprintf("using checksum: %s",(no_checksum)?"NO":"YES"))
# data size of data in bytes
data_sz = (header[0]&0x0000000f)
# number of data
data_n = header[1]
# redefine array given as argin
if(data_sz == 1) {
ubyte array @arrname[data_n]
} else if(data_sz == 2) {
ushort array @arrname[data_n]
} else if(data_sz == 4) {
ulong array @arrname[data_n]
} else if(data_sz == 8) {
ulong64 array @arrname[data_n]
} else {
_pepu_err
printf("unsupported data type: %d \n", data_sz)
sock_par(dev, "flush")
return -1
}
# the binary data should be in the socket, waiting for us
sock_par(dev, "timeout", 10)
n = sock_get(dev, @arrname)
_dance_debug(sprintf("bytes read: %d", (n*data_sz)))
if(data_n != n) {
_pepu_err
printf("missing data\n")
return -1
}
# check data validity
# WARNING: when data size is large (see with long64) the array_op()
# may return a wrong value because SPEC stores the sum in float/double
# with limited mantisse. Then it would be better to ignore checksum.
#
if(!no_checksum) {
bin_checksum = array_op("sum", @arrname) & 0xffffffff
if(bin_checksum != checksum) {
_pepu_err
printf("wrong checksum on binary data\n")
return -1
}
_dance_debug("checksum : OK")
}
# normal end
return data_n
}'
#%IU%(array_name)
#%MDESC%
# Work around to SPEC array_op("sum") loosing LSB bits.
# Much more slower than SPEC built-in of course.
# NOT VALIDATED
#
def _dance_checksum(arrname) '{
local ulong array sumval[1]
local cols i
cols = array_op("cols", @arrname)
for(i=0, sumval[0]=0;i<cols;i++) {
#sumval[0] += @arrname[i]
sumval[0] += (@arrname[i] & 0xffffffff)
}
printf("0x%08x\n", array_op("sum", @arrname))
printf("0x%08x\n", sumval[0])
}'
#%UU%
#%MDESC%
#
def dancedebug '{
dance_debug $*
}'
def dance_debug '{
global DANCE_DEBUG
# TODO: add debug levels
if(DANCE_DEBUG) {
print "DANCE debug is OFF"
DANCE_DEBUG = 0
} else {
print "DANCE debug is ON"
DANCE_DEBUG = 1
}
}'
#%IU%(msg)
#%MDESC%
#
def _dance_debug(msg) '{
global DANCE_DEBUG
if(DANCE_DEBUG == 0) {
return
}
printf("\t[DANCE]: %s\n", msg)
}'
#%IU%(string, case)
#%MDESC%
# Convert to lower (case==1) or to upper (case==0) case the string passed
#
def _dance_tocase(str, case) '{
string array str_a[length(str)]
local l
str_a = str
l = length(str)-1
for(;l>=0;l--) {
if(case)
str_a[l]=str_a[l]+(str_a[l]>=asc("A") && str_a[l]<=asc("Z"))*0x20;
else
str_a[l]=str_a[l]-(str_a[l]>=asc("a") && str_a[l]<=asc("z"))*0x20;
}
return(sprintf("%s", str_a))
}'
#%IU%(string)
#%MDESC%
# Return the lower string of the string passed
#
def _dance_tolower(str) '{return((str!="")?_dance_tocase(str, 1):"")}'
#%IU%(string)
#%MDESC%
# Return the upper string of the string passed
#
def _dance_toupper(str) '{return((str!="")?_dance_tocase(str, 0):"")}'
#%IU%(string)
#%MDESC%
#
def _dance_trim(str) '{
local b l
l = length(str)
if(l == 0) {
return ""
}
string array str_a[l]
str_a = str
l = l-1
for(;(l>=0)&&(str_a[l]==0x20);l--);
for(b=0;(b<l)&&(str_a[b]==0x20);b++);
return(substr(str,b+1,(l-b)+1))
}'
#
# ----------------------------- zap toolkit --------------------------------
# TODO: move this to zappepu.mac
#
#%IU%(stream_name, column)
#%MDESC%
# For tests only, do not use
#
def pepu_test_array_plot(sid, col) '{
global PEPU_STREAMS[]
local v_min v_max
local npts
arrname = PEPU_STREAMS[sid]["arr"]
npts = PEPU_STREAMS[sid]["nsample"]-1
if((npts == -1) || (!arrname)) {
_pepu_err
printf("nothing to plot\n")
return -1
}
long array arr_x[npts+1]
array_op("fill",arr_x)
double array a1[npts+1]
array_op("fill", a1)
a1 = a1+@arrname[0][col]
#v_min = array_op("min", @arrname[:npts][col])
#v_max = array_op("max", @arrname[:npts][col])
v_min = array_op("min", a1)
v_max = array_op("max", a1)
plot_cntl("erase")
plot_range("auto", "auto",v_min, v_max)
plot_cntl(sprintf("colors=%s",splot_col))
array_plot(arr_x[:npts], @arrname[:npts][col])
plot_cntl("colors=47:49:9:3:3")
array_plot(arr_x[:npts], a1)
# NOTE: the array_op() does not work on sub 2D arrays
double array a2[npts+1]
array_copy(a2, @arrname[][col])
return array_op("max", fabs(a2-a1))
}'
#%IU% hostname [[[[npts] freq] loops] start_trig] clock_trig]
#%MDESC%
# For tests only, do not use
# %BR%
# Expects pulses on IN6 at the
# same frequency that the sampling one. Can use an IcePAP axis
# controlled in speed, with motor_par(..., "jog_speed", hz), and its
# DB25 "Outpos" configured to "AXIS" as "source".
#%BR% freq given in Hz
#%BR% loops -1 means infinite loop
#%BR% start_trig is "SOFT"(default) "DI1" "DI2"
#%BR% clock_trig is "FREQ"(default) "DI1" "DI2"
#
def pepu_icepap_test '{
local pepuname
local hostname
local npts
local loops i
local tbeg
local intrig
if($# < 1) {
p "Usage: $0 hostname [[[[npts] freq] loops] start_trig] clock_trig]"
exit
}
pepuname = "bidon"
hostname = "$1"
sid = "encs"
npts = ($#>=2)?$2:1000
freq = ($#>=3)?$3:1000
loops = ($#>=4)?$4:1
intg = ($#>=5)?"$5":"SOFT"
clktg = ($#>=6)?"$6":"FREQ"
if(loops == -1) {
loops = pow(2, 32)
}
if(_pepu_setup(pepuname, hostname)) { exit }
if(_pepu_stream_add(pepuname, sid)) { exit }
if(_pepu_stream_source_add(sid, "in1")) { exit }
if(_pepu_stream_source_add(sid, "in6")) { exit }
if(_pepu_stream_nsample(sid, npts)) { exit }
if(_pepu_stream_fsample(sid, freq)) { exit }
if(_pepu_stream_trig(sid, intg, clktg)) { exit }
for(i=0;i<loops;i++) {
printf("---------------Loop: %d\n", i+1)
p date()
printf("Npts : %d\n", npts)
printf("Freq : %dHz\n", freq)
if(intrig) {
printf("Start: %s\n", intg)
printf("Clock: %s\n", clktg)
}
if(_pepu_stream_start(sid)) {
break
}
tbeg=time()
_pepu_stream_poll_read(sid)
printf("Elaps: %.1fsec\n", time()-tbeg)
err = pepu_test_array_plot(sid, 1)
printf("Error: %d\n", err)
if(err > 100) {
break
}
}
}'
#%IU% hostname
#%MDESC%
def pepu_test_renishaw '{
local pepuname
local hostname
local cmd ans
if($# < 1) {
p "Usage: $0 hostname"
exit
}
p $#
hostname = "$1"
pepuname = "bidon"
printf("Usig PePU: \"%s\"\n", hostname)
if(_pepu_setup(pepuname, hostname)) { exit }
printf("Configure IN1/2/3/4/5/6 to be RENISHAW compatible\n")
for(i=1;i<=6;i++) {
pepu_comm(hostname, sprintf("#CHCFG IN%d BISS", i))
pepu_comm(hostname, sprintf("#BISSCFG IN%d 32BITS 250000HZ", i))
pepu_comm(hostname, sprintf("#CHCFG IN%d ENABLE", i))
}
printf("Configure OUT7/8 to be RENISHAW compatible\n")
for(i=7;i<=8;i++) {
pepu_comm(hostname, sprintf("#CHCFG OUT%d BISS", i))
pepu_comm(hostname, sprintf("#CHCFG OUT%d ENABLE", i))
}
printf("Configure OUT7/8 as average of IN1/2/3/4\n")
pepu_comm(hostname, "#CALCCFG calc7 (in1+in2+in3+in4)/4")
pepu_comm(hostname, "#CHSRC out7 calc7")
pepu_comm(hostname, "#CHSRC out8 calc7")
}'
#%MACROS%
#%IMACROS%
#%AUTHOR% MP+FLM+RH BLISS (Original 9/2015).
# %BR%$Revision: 1.3 $ / $Date: 2016/11/21 11:53:21 $
#%TOC%
|