#%TITLE% nhq_mac_hdw.mac.mac
#$Revision: 1.4 $
#%NAME% Macros for a NHQ high quality power supply
#%DESCRIPTION%
# The macros provide users with an interface using macro motors/counters between
# SPEC and a NHQ high quality power supply.
#%INTERNALS%
# You may declare a motor and a counter, even for the same
# device! The macro motor/counter macros can handle that. Possible channel
# numbers are %B%1%B% and %B%2%B%.
#%BR% %BR% %BR% %BR% %BR% %BR% %BR% %BR% %BR%
#%SETUP%
#%BR% %BR%Declare a %B%motor\0controller%B%:
#%BR% %BR%
#%PRE%
#MOTORS\0\0\0\0DEVICE\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ADDR\0\0<>MODE\0\0NUM\0\0\0\0\0\0\0\0\0\0\0\0\0<>TYPE%BR%
#\0\0\0YES\0\0\0\0\0\0\0NHQ\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\04\0\0\0\0\0\0\0\0\0\0\0\03\0\0\0\0\0\0\0Macro Motors
#%PRE%
# %BR%
# Please put the index number of your serial line into the ADDR field (alphanum,
# hit "'" first).
# %BR%
#Then create the macro motor:
#%PRE%
#Number:\0<>Controller\0\0\0\0\0\0\0\0\0\0\00:\0MAC_MOT
#%BR%
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00/1
#%BR%
#Name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NHQ1
#%BR%
#Mnemonic\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0nhq1
#%BR%
#Steps per degree/mm\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01\0\0\0<------
#%BR%
#Sign of user * dial\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Backlash [steps]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00\0\0\0<------
#%BR%
#Steady-state rate [Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\02\0\0\0<------
#^^^^^^^^^^^^^^^^^used as ramping value: between 2 and 255 V/s
#%BR%
#Base rate [Hz]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Acceleration time [msec]\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01
#%BR%
#Motor accumulator\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00
#%BR%
#Restrictions <>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NONE
#%BR%
#
#%BR%
#Dial = accumulator / steps
#%BR%
#\0\0High limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01000.0000
#%BR%
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#%BR%
#\0\0Low limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-1000.0000
#%BR%
#User = sign * dial + offset
#%BR%
#\0\0Offset\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#%BR%
#\0\0`High' limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\01000.0000
#%BR%
#\0\0Current\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00.0000
#%BR%
#\0\0`Low' limit\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0-1000.0000
#%PRE%
#%BR% %BR% %BR% %BR% %BR% %BR% %BR% %BR% %BR%
# Now hit `m` twice to move to the third motor config screen
#%BR% %BR%
#%PRE%
#\0\0Number:\0<>Controller\0\0\0\0\0\00:\0MAC_MOT
#Unit/[Module/]Channel\0\0\0\0\0\0\0\0\0\0\0\0\0\00/1
#Name\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NHQ1
#Mnemonic\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0nhq1
#
#Encoder\0steps\0per\0deg/mm
#Step\0mode\0(0=full,1=half)
#Linear/Rotary\0(1=rotary)
#Disable\0limit\0checks
#Readback\0slop\0[steps]
#Hardware\0read\0mode\0<>\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0NQ\0\0\0<------------
#%PRE%
#%BR% %BR%Now declare a %B%scaler\0controller%B%:
#%PRE%
#SCALERS\0\0\0\0\0\0\0\0\0DEVICE\0\0\0\0\0\0\0\0\0\0ADDR\0\0<>MODE\0\0NUM\0\0\0\0\0\0\0\0\0\0\0\0\0<>TYPE%BR%
#\0\0\0YES\0\0\0\0\0\0\0\0\0\0\0\0\0NHQ\0\0\0\0\0\0\0\0\0\0\0\0\04\0\0\0\0\0\0\0\0\0\0\0\03\0\0\0\0\0\0Macro Counter
#%PRE%%BR%
#%BR% %BR%
# The %B%counter%B% is then configured as :
#%PRE%
#Number\0\0\0\0\0\0\0\0Name\0\0Mnemonic\0\0<>Device\0\0Unit\0\0Chan\0\0\0<>Use\0As\0\0Scale\0Factor
#\0\0\0\0\04\0\0\0\0\0\0nhq1_c\0\0\0\0nhq1_c\0\0\0MAC_CNT\0\0\0\0\00\0\0\0\0\01\0\0\0\0counter\0\0\0\0\0\0\0\0\0\0\0\0\01
#%PRE%%BR%
#%END%
#%HISTORY%
#$Log: nhq_mac_hdw.mac,v $
#Revision 1.4 2011/02/03 10:56:12 witsch
#move the colored text macros before their first usage.
#
#Added more decriptive text to the steps_mm config value.
#
#.,
#
#Revision 1.3 2010/09/28 11:46:44 witsch
#some minor errors, which had not been seen, testing with the simulation
#device, have been corrected. Testing with a real device.
#
#Revision 1.2 2010/09/22 13:41:59 witsch
#little changes for th simulation.
#
#Revision 1.1 2010/09/20 15:42:58 witsch
#Initial revision
#
if (!(whatis("__nhqdebug") & 2)) rdef __nhqdebug \'#$*\'
if (!(whatis("__nhqsimu") & 2)) rdef __nhqsimu \'#$*\'
#%UU%
#%MDESC% toggle debug mode for the present macros.
def nhq_debug '{
if ((whatis("__nhqdebug")>>16) <= 4) { # just a # sign -> off
rdef __nhqdebug "eprint"
print "NHQ debug is ON"
} else {
rdef __nhqdebug \'#\$*\' # that are three bytes
print "NHQ debug is OFF"
}
}
'
#%UU%
#%MDESC% toggle debug mode for the present macros.
def nhq_simu '{
if ((whatis("__nhqsimu")>>16) <= 4) { # just a # sign -> off
rdef __nhqsimu "__nhq_simu_func"
print "NHQ simu is ON"
} else {
rdef __nhqsimu \'#\$*\' # that are three bytes
print "NHQ simu is OFF"
}
}
'
def _nhq_put(addr, str) '{
local _str, _str_len
__nhqdebug "_nhq_put(" addr ", " str ")"
_str = str "\r\n"
_str_len = length(_str)
__nhqsimu _str ; return(0)
if (ser_put(addr, _str) != _str_len) {
tty_cntlred
eprint "Communication error with NHQ!"
tty_cntlnotred
return(".error.")
}
# controller echoes input !!!!
local answer
answer = _nhq_get(addr)
# is answer equal to _str
if (index(answer, _str) != 1) {
tty_cntlred
eprint "Communication error with NHQ! Sent and received strings differ!", answer, _str
eprint length(_str), length(answer)
tty_cntlnotred
return(".error.")
}
}
'
def _nhq_get(addr) '{
local str
__nhqsimu ; return(__nhq["ANSWER"])
str = ser_get(addr, 0)
__nhqdebug "answer = " str
return(str)
}
'
# except for the command G[12] every command should yield a number. Numbers are
# like +0022. Without proper treatment, this value will be interpreted as octal.
# treat the result with a sscanf to make it decimal!
def _nhq_io(addr, str) '{
local answer, val
if(_nhq_put(addr, str) == ".error.") {
tty_cntlred
eprint "Error in function _nhq_put!"
tty_cntlnotred
return(".error.")
}
answer = _nhq_get(addr)
# evaluate contents
if (sscanf(answer, "%d", val)) { # most likely a value like +0022
return(val)
}
else if (sscanf(answer, "%g", val)) { # for cmd I1 could be xeyyy
return val
}
else {
if (answer == "?WCN\r\n") {
tty_cntlred
eprint "Wrong Channel"
tty_cntlnotred
return ".error."
}
else if(answer == "????\r\n") {
tty_cntlred
eprint "Syntax error"
tty_cntlnotred
return ".error."
}
else if(answer == "?TOT\r\n") {
tty_cntlred
eprint "Timeout error"
tty_cntlnotred
return ".error."
}
else if (index(answer, "? UMAX=")) {
sscanf(substr(answer, index(answer, "=") +1), "%d", val)
tty_cntlred
eprint "Set voltage exceeds voltage limit", val, "!!!"
tty_cntlnotred
return ".error."
}
return(answer)
}
}
'
#%IU%(mnum, type, unit, mod, chan)
#%MDESC%
# Called by spec
def NHQ_config(mnum, type, unit, mod, chan) '{
__nhqdebug "Configuring NHQ", mnum, type, unit, mod, chan
if ((type == "..") && !whatis("__nhq")) {
global __nhq[] # used for detection if config has been run.
ser_par(NHQ_addr, "flush", 2)
if (ser_put(NHQ_addr, "\r\n") != 2) {
return ".error."
}
return(0)
}
if (type == "mot") {
if ((chan = motor_par(mnum, "channel")) == 0) {
tty_cntlred
eprint "Channel number 0 is not possible for motor", \
motor_mne(mnum)
tty_cntlnotred
return ".error."
}
NHQ_par(mnum, "velocity", "set", motor_par(mnum, "velocity"))
}
else if (type == "cnt") {
if ((chan = counter_par(mnum, "channel")) == 0) {
tty_cntlred
eprint "Channel number 0 is not possible for counter", \
cnt_mne(mnum)
tty_cntlnotred
return ".error."
}
}
}
'
#%IU%
#%MDESC%
# Called by spec
def NHQ_cmd(mnum, cmd, p1, p2, p3) '{
local chan, tension, str, addr
__nhqdebug "*** NHQ_cmd: mnum", mnum, "cmd", cmd, "p1", p1, "p2", p2, "p3", p3
if (mnum != "..") {
if (cmd == "start_one") {
# start counter, when it is one
if (p2 == 0) {
return
}
# must be a motor then
chan = motor_par(mnum, "channel")
addr = motor_par(mnum, "address")
# send command "D1=xxx" : Set voltage for channel 1
str = "D" chan "=" int(p1)
_nhq_io(addr, str)
# send command "G1" : Start Voltage change for channel 1
str = "G" chan
str = _nhq_io(addr, str)
__nhqdebug "*** ramp command, answer:", str
}
else if ((cmd == "position") || (cmd == "counts")) { # counts is for the counter
# dirty trick: if p1 is 16, it`s a counter
if (cmd == "counts") {
chan = counter_par(mnum, "channel")
addr = counter_par(mnum, "address")
} else {
chan = motor_par(mnum, "channel")
addr = motor_par(mnum, "address")
}
str = "U" chan
tension = _nhq_io(addr, str)
__nhqdebug "tension channel", chan, "is:", tension
return(tension)
}
else if (cmd == "get_status") {
local aux[]
chan = motor_par(mnum, "channel")
addr = motor_par(mnum, "address")
str = "S" chan
str = _nhq_io(addr, str)
if (index(str, "H2L\r\n") || index(str, "L2H\r\n")) {
return(2)
}
return(0)
}
}
# Documentation sais synching with a "\r\n" is necessary. The
# multiple flush commands seem unnecessary.
# else {
# if (cmd == "prestart_all") {
# ser_par(NHQ_ADDR, "flush", 2)
# __nhqdebug "flushed serial line", NHQ_ADDR
# }
# }
}
'
#%IU%
#%MDESC%
# Called by spec
def NHQ_par(mnum, cmd, p1, p2) '{
if (mnum == ".." ) {
return
}
__nhqdebug "*** NHQ_par",mnum, cmd, p1, p2
local chan, addr, str
chan = motor_par(mnum, "channel")
addr = motor_par(mnum, "address")
if (cmd == "velocity" && p1 == "set") {
local str
str = "V" chan "=" p2
_nhq_io(addr, str)
}
}
'
#%UU% mne ramp
#%MDESC%
# Set ramp (2 to 255 V/s) for motor mne to ramp
def nhq_ramp '{
local mnum
if ($# != 2) {
eprint "Please give motor mnemonic and ramp value as argument!"
eprint "Ramp value can be 2 to 255 V/s."
eprint "Exit!"
exit
}
if ((mnum = motor_num($1)) == -1) {
print "Invalid mnemonic - no such motor :", $1
exit
}
if (motor_par($1, "device_id") != "NHQ") {
print "This is not a NHQ motor :", $1
exit
}
if (int($2) > 255) }
print "Value too big. Device will use 255 V/s."
} else if (int($2) < 2) }
print "Value too small. Device will use 2 V/s."
}
motor_par(mnum, "velocity", $2)
}'
#%UU% mne
#%MDESC%
# Prints Status, Voltage, Ramp of NHQ for motor mne
def nhq_info '{
if ($# == 0) {
eprint "Please give motor mnemonic as argument!"
eprint "Exit!"
exit
}
local mnum
if ((mnum = motor_num($1)) == -1) {
eprint "Invalid mnemonic - no such motor :", $1
exit
}
_nhq_info(mnum)
}'
#%IU% (mnum)
#%MDESC%
# Prints Status, Voltage, Ramp of NHQ (bench -> ~1.8s / channel)
def _nhq_info(mnum) '{
local str, val, chan, addr
chan = motor_par(mnum, "channel")
addr = motor_par(mnum, "address")
print "- NHQ - ask status of", mnam = motor_name(mnum)
print "Id (unit nb; software version; U max ; Imax) :", _nhq_id(addr)
print "SerialLine :", addr , " \tChannel :", chan
print "Status :", _nhq_status(addr, chan), " \tmodule status :", _nhq_mod_status(addr, chan)
str = "M" chan
print "Voltage :", NHQ_cmd(mnum, "position") " V" " \tU limit :", _nhq_io(addr, str) "%"
# do we really need polarity, the value returned has a sign
#print "Polarity :", (fabs(A[mnum]) == A[mnum]) ? "positiv" : "negative"
local curr, currlim, currtrip
str = "I" chan; curr = _nhq_io(addr, str)
str = "N" chan; currlim = _nhq_io(addr, str)
str = "L" chan; currtrip = _nhq_io(addr, str)
print "Current :", curr " uA" " \tI limit : " currlim "%", \
" Current Trip :", currtrip
str = "V" chan
print "Ramp speed :", _nhq_io(addr, str), " V/s"
print ""
}'
#%IU% (mnum)
#%MDESC%
# Returns status of one NHQ channel. "S" command
def _nhq_status(addr, chan) '{
local str
# "S1"
str = "S" chan
if((str = _nhq_io(addr, str)) == ".error.") {
return ""
}
local aux[]
# before this would be substr(str,4)
# but there might be simply an "ON\r\n"
if (split (str, aux, "=") > 1) {
str = aux[1]
}
split(str, aux, "\r")
return (aux[0])
}'
#%IU% (mnum)
#%MDESC%
# Returns Module Status of one NHQ module. "T" command
def _nhq_mod_status(addr, chan) '{
local str, _s
# "T1"
str = "T" chan
if((str = _nhq_io(addr, str)) == ".error.") {
return ""
}
__nhqdebug "Module Status:", str
_s = ""
if (val >> 8) {
_s = "QUA"
}
if (val >> 7) {
_s = _s " ERR"
}
if (val >> 6) {
_s = _s " INH"
}
if (val >> 5) {
_s = _s " KILL_ENA"
}
if (val >> 4) {
_s = _s " OFF"
}
if (val >> 3) {
_s = _s " POL"
}
if (val >> 2) {
_s = _s " MAN"
}
if (val >> 1) {
_s = _s " T?"
}
return (_s)
}'
#%IU% (mnum)
#%MDESC%
# Returns ID of one NHQ channel.
def _nhq_id(addr) '{
return (_nhq_io(addr, "#"))
}'
# some cosmetics
def tty_cntlred '{
printf("[47m[1;31m")
}
'
def tty_cntlnotred '{
printf("[0m")
}
'
# this is an attempt to come around the problem with the macro motor macros
# being loaded at the end of the config/setup, thus not executing the
# NHQ_config function. Variable remain uninitialised. We need a reconfig
if (!whatis("__nhq")) {
tty_cntlred
eprint "Make sure to do a reconfig for the NHQ high quality power supply!!!"
tty_cntlnotred
}
def __nhq_delete_old_macros() '{
# delete all the old macros to avoid confusion
x = "nhq_setup nhq_unsetup _nhq_write"
x = x " nhq_set_voltage _nhq_set_voltage _nhq_get_voltage _nhq_get_voltage_limit"
x = x " _nhq_get_current _nhq_get_current_limit _nhq_get_current_trip"
x = x " _nhq_set_ramp _nhq_get_ramp nhq_pseudo_setup nhq_pseudo_unsetup _nhq_getpangles"
x = x " _nhq_checkall _nhq_getcounts nhq_on nhq_off"
local y[]
global isthereone
split( x, y)
for (name in y) {
bla = y[name]
str = "if (whatis(\"" bla "\") & 2) { undef " bla "; isthereone = 1; }"
eval(str)
}
if (isthereone) {
eprint "nhq_mac_hdw.mac has deleted all macros contained in the nhq.mac file!"
}
unglobal isthereone
}
'
__nhq_delete_old_macros()
undef __nhq_delete_old_macros
def __nhq_simu_func '{
if ($# == 0) {
__nhqdebug "__nhq_simu_func: answer", __nhq["ANSWER"]
}
else if ($# > 1) {
tty_cntlred
eprint "SIMULATION: wrong number of args in __nhq_simu_func!"
tty_cntlnotred
}
else {
# take the string in $1 apart.
local cmd, chan, val
cmd = substr($1, 1, 1)
chan = substr($1, 2, 1)
__nhqdebug "__nhq_simu_func: cmd", cmd, "chan", chan, "\$1", $1
# store command
if ((cmd == "U") || (cmd == "S")) {
local tdiff, tneed
tdiff = time() - __nhq[chan]["startt"]
tneed = fabs(__nhq[chan]["oldval"] - __nhq[chan]["val"]) / \
__nhq[chan]["rampspeed"]
if (tdiff < tneed) {
local sign
sign = (__nhq[chan]["oldval"] < __nhq[chan]["val"]) ? 1 : -1
val = __nhq[chan]["oldval"] + tdiff * \
sign * __nhq[chan]["rampspeed"]
} else {
val = __nhq[chan]["val"]
__nhq[chan]["status"] = "ON\r\n" # move terminated
}
if (cmd == "S") {
__nhq["ANSWER"] = __nhq[chan]["status"]
}
else {
__nhq["ANSWER"] = val + rand(val * .1)
}
}
else if (cmd == "D") {
local aux[]
if (split($1, aux, "=") == 2) {
__nhq[chan]["oldval"] = __nhq[chan]["val"]
__nhq[chan]["val"] = int(aux[1])
__nhq["ANSWER"] = ""
}
else {
__nhq["ANSWER"] = __nhq[chan]["val"]
}
}
else if (cmd == "G") {
__nhq[chan]["status"] = "H2L\r\n" # just for moving
__nhq[chan]["startt"] = time()
__nhq["ANSWER"] = "S" chan "=" __nhq[chan]["status"]
}
else if (cmd == "V") { # 2 to 255 V/s
local aux[]
if (split($1, aux, "=") == 2) {
__nhq[chan]["rampspeed"] = int(aux[1])
__nhq["ANSWER"] = ""
}
else {
__nhq["ANSWER"] = __nhq[chan]["rampspeed"]
}
}
else {
__nhq["ANSWER"] = ""
}
}
}
'
#%MACROS%
#%IMACROS%
#%AUTHOR%
# nhq_mac_hdw.MAC HW 9/2010
# %BR%derived from nhq.mac
#%TOC%
|