Files
sics/site_ansto/instrument/config/environment/knauer_pump.sct
2014-10-07 15:03:43 +11:00

483 lines
14 KiB
Tcl

#
# Template driver for the Knauer BlueShadow Pump 40P
# vim: ft=tcl ts=8 sts=2 sw=2 expandtab autoindent smartindent nocindent
#
driver knauer_pump = {
debug_threshold = 0;
vendor = knauer; device = pump40p; protocol = knauer_ap;
class = environment;
simulation_group = environment_simulation;
#
group dummy = {
type = text; readable = 1; data = false; control = false; nxsave = false;
var status = { read_command = 'STATUS?'; read_function = read_status; property real_data = ' '; }
var glp = { read_command = 'GLP?'; read_function = read_glp; property real_data = ' '; }
}
group pump = {
var remote = {
type = int;
readable = 1; read_command = 'REMOTE?'; read_function = remote_read;
writeable = 1; write_function = remote_write;
allowed = '0,1';
}
var state = {
type = text;
readable = 1;
read_command = ' ';
fetch_function = state_fetch;
}
var status = {
type = text;
readable = 1;
read_command = ' ';
fetch_function = status_fetch;
}
group volume = {
var pval = {
type = float;
readable = 1;
read_command = ' ';
fetch_function = volume_fetch;
#checkrange_function = volume_reject;
property 'units' = 'mL';
}
var setp = {
type = float;
writeable = 1;
write_command = ' ';
write_function = pump_write;
driveable = pump/volume/pval;
checkstatus_function = pump_checkstatus;
halt_function = pump_halt;
lowerlimit = 0; upperlimit = 100; tolerance = 0.01;
readable = 1;
read_command = ' ';
fetch_function = pump_fetch;
property 'units' = 'mL';
property this_state = 0;
}
}
group ratio = {
var pval = {
type = text;
readable = 1; read_command = ' '; fetch_function = ratio_fetch;
property 'units' = 'percent';
}
var setp = {
type = text;
value = '25/25/25/25';
writeable = 1; write_command = ' '; write_function = ratio_write; checkrange_function = ratio_check;
property 'units' = 'percent';
}
}
group flow = {
var pval = {
type = float;
readable = 1; read_command = ' '; fetch_function = flow_fetch;
property 'units' = 'mL/min';
}
var setp = {
type = float;
value = 1.0;
writeable = 1; write_command = ' '; write_function = flow_write;
lowerlimit = 0; upperlimit = 10;
property 'units' = 'mL/min';
}
}
}
group grp_stuff = {
readable = 600;
type = text;
data = false; control = false; nxsave = false;
var an_out = { read_command = 'AN_OUT?'; }
var boardinfo = { read_command = 'BOARDINFO?'; }
var config = { read_command = 'CONFIG?'; }
var cprofinfo = { read_command = 'CPROFINFO?'; }
var dout = { read_command = 'DOUT?'; }
var error = { read_command = 'ERROR?'; }
var errors = { read_command = 'ERRORS?'; }
var flushpmp = { read_command = 'FLUSHPMP?'; }
var head = { read_command = 'HEAD?'; }
var head_par = { read_command = 'HEAD_PAR?'; }
var identify = { read_command = 'IDENTIFY?'; }
var lpg = { read_command = 'LPG?'; }
var oem = { read_command = 'OEM?'; }
var opt = { read_command = 'OPT?'; }
var plim = { read_command = 'PLIM?'; }
var pressure = { read_command = 'PRESSURE?'; }
var prfastacq = { read_command = 'PRFASTACQ?'; }
var purge = { read_command = 'PURGE?'; }
var remote = { read_command = 'REMOTE?'; }
var rfid = { read_command = 'RFID?'; }
var service = { read_command = 'SERVICE?'; }
var sysinfo = { read_command = 'SYSINFO?'; }
var 'units' = { read_command = 'UNITS?'; }
var valves = { read_command = 'VALVES?'; }
}
group grp_glp = {
type = text;
readable = 1;
fetch_function = fetch_from_glp;
var board_time = { read_command = '0'; }
var motor_time = { read_command = '1'; }
var head_count = { read_command = '3'; }
var head_time = { read_command = '4'; }
var head_volm = { read_command = '5'; }
var head_voln = { read_command = '6'; }
var head_pwrhi = { read_command = '7'; }
var head_pwrlo = { read_command = '8'; }
var pump_revs = { read_command = '9'; }
var pump_volm = { read_command = '10'; }
var pump_voln = { read_command = '11'; }
var pump_pwrhi = { read_command = '12'; }
var pump_pwrlo = { read_command = '13'; }
}
group grp_status = {
type = text;
readable = 1;
fetch_function = fetch_from_status;
var state = { read_command = '1'; }
var cur_error = { read_command = '2'; }
var cur_run_time = { read_command = '3'; }
var flow_rate = { read_command = '4'; }
var lpg_0 = { read_command = '5'; }
var lpg_1 = { read_command = '6'; }
var lpg_2 = { read_command = '7'; }
var lpg_3 = { read_command = '8'; }
var evt_0 = { read_command = '9'; }
var evt_1 = { read_command = '10'; }
var evt_2 = { read_command = '11'; }
var evt_3 = { read_command = '12'; }
var evt_4 = { read_command = '13'; }
var evt_5 = { read_command = '14'; }
var evt_6 = { read_command = '15'; }
var evt_7 = { read_command = '16'; }
var cur_pres = { read_command = '17'; }
var start_in = { read_command = '18'; }
var error_in = { read_command = '19'; }
}
#
# Ensure the pump starts up in REMOTE mode
#
code mkDriver = {%%
hset ${scobj_hpath}/pump/remote 1
%%}
#
# These functions handle the real_data returned by the pump for the GLP? command
#
code read_glp = {%%
if { [string equal -nocase -length 6 ${data} "ERROR:"] } {
} else {
set dlist [split [lindex [split ${data} ":"] 1] ","]
sct real_data "[join [lrange ${dlist} 0 end] ,]"
set data "Hidden in real_data property"
}
%%}
code fetch_from_glp = {%%
set index ${cmd_str}
set data [hgetpropval ${tc_root}/dummy/glp real_data]
set dlist [split ${data} ","]
if { [llength ${dlist}] > ${index} } {
sct result [lindex ${dlist} ${index}]
} else {
sct result ""
}
set cmd "@@NOSEND@@"
%%}
#
# These functions handle the real_data returned by the pump for the STATUS? command
#
code read_status = {%%
set dlist [split [lindex [split ${data} ":"] 1] ","]
sct real_data "[join [lrange ${dlist} 0 end] ,]"
set data "Hidden in real_data property"
%%}
code fetch_from_status = {%%
set index ${cmd_str}
set data [hgetpropval ${tc_root}/dummy/status real_data]
set dlist [split ${data} ","]
if { [llength ${dlist}] > ${index} } {
sct result [lindex ${dlist} ${index}]
} else {
sct result ""
}
set cmd "@@NOSEND@@"
%%}
#
# Decode the status from the real_data to PUMPING if it is pumping else IDLE
#
code status_fetch = {%%
set index 1
set data [hgetpropval ${tc_root}/dummy/status real_data]
set dlist [split ${data} ","]
set status_code [lindex ${dlist} ${index}]
set cmd "@@NOSEND@@"
if { ${status_code} == 3 } {
sct result "PUMPING"
} else {
sct result "IDLE"
}
%%}
#
# Decode the state from the real_data to one of the documented strings
#
code state_fetch = {%%
set index 1
set data [hgetpropval ${tc_root}/dummy/status real_data]
set dlist [split ${data} ","]
if { [llength ${dlist}] > ${index} } {
set state_code [lindex ${dlist} ${index}]
} else {
set state_code "0"
}
set cmd "@@NOSEND@@"
if { ${state_code} < 0 || ${state_code} > 9 } {
sct geterror "Invalid device_state ${state_code}"
error "[sct geterror]"
}
set slist [list "SYS_ST_INITIALIZING" \
"SYS_ST_OFF" \
"SYS_ST_IDLE" \
"SYS_ST_RUN" \
"SYS_ST_HOLD" \
"SYS_ST_PURGE" \
"SYS_ST_STANDBY" \
"SYS_ST_FAILED" \
"SYS_ST_RUNATEND" \
]
sct result [lindex ${slist} ${state_code}]
%%}
#
#
code flow_fetch = {%%
set index 4
set data [hgetpropval ${tc_root}/dummy/status real_data]
set dlist [split ${data} ","]
if { [llength ${dlist}] > ${index} } {
set flow_pv [lindex ${dlist} 4]
} else {
set flow_pv 0.0
}
sct result [expr {0.001 * ${flow_pv}}]
set cmd "@@NOSEND@@"
%%}
code flow_write = {%%
set data [sct target]
set cmd "@@NOSEND@@"
set nextState idle
if { ${data} != [sct oldval] } {
debug_log ${tc_root} 1 "[sct] changed to new:${data}, from old:[sct oldval]"
sct oldval ${data}
sct update ${data}
sct utime readtime
}
%%}
#
#
code ratio_check = {%%
set rlist [split ${setpoint} /]
if { [llength ${rlist}] != 4 } {
sct geterror "${setpoint} has [llength ${rlist}] components, needs 4"
error [sct geterror]
}
set sum [expr [lindex ${rlist} 0] + [lindex ${rlist} 1] + [lindex ${rlist} 2] + [lindex ${rlist} 3]]
if { ${sum} != 100 } {
sct geterror "sum is ${sum}, must be 100"
error [sct geterror]
}
%%}
code ratio_fetch = {%%
set data [hgetpropval ${tc_root}/dummy/status real_data]
set dlist [split ${data} ","]
set ratio_vals "[lindex ${dlist} 5]/[lindex ${dlist} 6]/[lindex ${dlist} 7]/[lindex ${dlist} 8]"
sct result ${ratio_vals}
set cmd "@@NOSEND@@"
%%}
code ratio_write = {%%
set data [sct target]
set cmd "@@NOSEND@@"
set nextState idle
if { ${data} != [sct oldval] } {
debug_log ${tc_root} 1 "[sct] changed to new:${data}, from old:[sct oldval]"
sct oldval ${data}
sct update ${data}
sct utime readtime
}
%%}
#
#
code remote_read = {%%
if { [string equal -length 7 ${data} "REMOTE:"] } {
set data [lindex [split ${data} :] 1]
} else {
sct geterror "bad response"
error "[sct geterror]"
}
%%}
code remote_write = {%%
if { ${par} == 0 } {
set cmd "LOCAL"
} else {
set cmd "REMOTE"
}
%%}
#
#
code volume_fetch = {%%
set data [hgetpropval ${tc_root}/dummy/glp real_data]
set dlist [split ${data} ","]
if { [llength ${dlist}] > 11 } {
set pump_volm [lindex ${dlist} 10]
set pump_voln [lindex ${dlist} 11]
set pump_volume [expr {${pump_volm} + 0.000001 * ${pump_voln}}]
} else {
set pump_volume 0.0
}
sct raw_volume ${pump_volume}
if { [hpropexists [sct] base_volume] } {
set pump_volume [expr {${pump_volume} - [sct base_volume]}]
} elseif { [hpropexists [sct] raw_volume] } {
sct base_volume [sct raw_volume]
}
sct result [format "%.2f" ${pump_volume}]
set cmd "@@NOSEND@@"
%%}
##########
code pump_write = {%%
hsetprop ${tc_root}/[sct driveable] base_volume [hgetpropval ${tc_root}/[sct driveable] raw_volume]
hset ${tc_root}/[sct driveable] 0.0
set cmd "REMOTE"
sct this_state 1
sct pumping 1
set data ${par}
if { ${data} != [sct oldval] } {
debug_log ${tc_root} 1 "[sct] changed to new:${data}, from old:[sct oldval]"
sct oldval ${data}
sct update ${data}
sct utime readtime
}
%%}
code pump_fetch = {%%
if { [sct this_state] > 0 } {
set flow_tgt [expr {int(1000.0 * [hval ${tc_root}/pump/flow/setp])}]
set ratio_tgt [join [split [hval ${tc_root}/pump/ratio/setp] /] ,]
set time_tgt [expr {int(60000.0 * 1000.0 * [sct target] / ${flow_tgt})}]
set time_1 [expr {${time_tgt} - 500}]
set time_2 [expr {${time_tgt} + 500}]
set nextState noResponse
if { [sct this_state] == 1 } {
set cmd "TT_LOAD:1"
sct this_state [expr {[sct this_state] + 1}]
} elseif { [sct this_state] == 2 } {
set cmd "TT_SET:0,0,${flow_tgt},${ratio_tgt},0,0,0,0,0,0,0,0"
sct this_state [expr {[sct this_state] + 1}]
} elseif { [sct this_state] == 3 } {
set cmd "TT_SET:1,${time_1},${flow_tgt},${ratio_tgt},0,0,0,0,0,0,0,0"
sct this_state [expr {[sct this_state] + 1}]
} elseif { [sct this_state] == 4 } {
set cmd "TT_SET:2,${time_2},0,${ratio_tgt},0,0,0,0,0,0,0,0"
sct this_state [expr {[sct this_state] + 1}]
} elseif { [sct this_state] == 5 } {
set cmd "START:1,0"
sct this_state 0
} else {
sct this_state 0
set cmd "@@NOSEND@@"
set nextState idle
}
} else {
set cmd "@@NOSEND@@"
set nextState idle
if { [hpropexists [sct] pumping] && [sct pumping] } {
if { [hpropexists [sct] driving] && [sct driving] } {
pump_checkstatus "${tc_root}"
}
set new_value [hval ${tc_root}/pump/status]
set old_value [sct oldval]
if {${new_value} != ${old_value}} {
sct oldval ${new_value}
if {${old_value} == "PUMPING" && ${new_value} == "IDLE"} {
set cmd "STOP"
set nextState noResponse
sct result ""
sct driving 0
sct pumping 0
}
}
}
}
%%}
code pump_halt = {%%
set flow_tgt 0
set ratio_tgt [join [split [hval ${tc_root}/pump/ratio_sp] /] ,]
set cmd "STOP"
sct send ${cmd}
%%}
##########
code volume_write = {%%
hsetprop ${tc_root}/[sct driveable] base_volume [hgetpropval ${tc_root}/[sct driveable] raw_volume]
hset ${tc_root}/[sct driveable] 0.0
set flow_tgt [expr {int(1000.0 * [hval ${tc_root}/pump/flow_sp])}]
set ratio_tgt [join [split [hval ${tc_root}/pump/ratio_sp] /] ,]
set cmd "RAMP:0,${flow_tgt},${ratio_tgt},0,0,0,0,0,0,0,0,3"
sct pumping 1
set data ${par}
if { ${data} != [sct oldval] } {
debug_log ${tc_root} 1 "[sct] changed to new:${data}, from old:[sct oldval]"
sct oldval ${data}
sct update ${data}
sct utime readtime
}
%%}
code volume_checkpumping = {%%
set cmd "@@NOSEND@@"
set nextState idle
if { [hpropexists [sct] pumping] && [sct pumping] } {
if { [hpropexists [sct] driving] && [sct driving] } {
volume_checkstatus "${tc_root}"
}
set sp "[sct target]"
set pv "[hval ${tc_root}/[sct driveable]]"
if { (${sp} - ${pv}) <= [sct tolerance] } {
set flow_tgt 0
set ratio_tgt [join [split [hval ${tc_root}/pump/ratio_sp] /] ,]
set cmd "RAMP:0,${flow_tgt},${ratio_tgt},0,0,0,0,0,0,0,0,2"
set nextState noResponse
sct result ""
sct driving 0
sct pumping 0
}
}
%%}
code volume_halt = {%%
set flow_tgt 0
set ratio_tgt [join [split [hval ${tc_root}/pump/ratio_sp] /] ,]
set cmd "RAMP:0,${flow_tgt},${ratio_tgt},0,0,0,0,0,0,0,0,2"
sct send ${cmd}
%%}
code volume_reject = {%%
sct geterror "cannot use hset on [sct]"
error "[sct geterror]"
%%}
}