diff --git a/site_ansto/instrument/config/environment/knauer_pump.sct b/site_ansto/instrument/config/environment/knauer_pump.sct index 63a616f5..881caa4c 100644 --- a/site_ansto/instrument/config/environment/knauer_pump.sct +++ b/site_ansto/instrument/config/environment/knauer_pump.sct @@ -39,6 +39,7 @@ driver knauer_pump = { readable = 1; read_command = ' '; fetch_function = volume_fetch; + read_function = volume_read; property 'units' = 'mL'; } var setp = { @@ -46,6 +47,7 @@ driver knauer_pump = { writeable = 1; write_command = ' '; write_function = volume_write; + check_function = volume_check; driveable = pump/volume/pval; checkstatus_function = volume_checkstatus; halt_function = volume_halt; @@ -53,6 +55,7 @@ driver knauer_pump = { readable = 1; read_command = ' '; fetch_function = volume_fsm; + read_function = volume_store; property 'units' = 'mL'; property this_state = 0; } @@ -90,7 +93,7 @@ driver knauer_pump = { # Ensure the pump starts up in REMOTE mode # code mkDriver = {%% - hset ${scobj_hpath}/pump/remote 1 + #hset ${scobj_hpath}/pump/remote 1 %%} # # These functions handle the real_data returned by the pump for the GLP? command @@ -194,9 +197,21 @@ driver knauer_pump = { 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]] + set sum 0 + for {set i 0} {$i < 4} {incr i} { + set cmp [lindex ${rlist} ${i}] + if { ![string is integer -strict ${cmp}] } { + sct geterror "component [expr {${i} + 1}] is not integer: \"${cmp}\"" + error [sct geterror] + } + if { !(${cmp} >= 0 && ${cmp} <= 100) } { + sct geterror "component [expr {${i} + 1}] is not between 0 and 100: \"${cmp}\"" + error [sct geterror] + } + set sum [expr {${sum} + ${cmp}}] + } if { ${sum} != 100 } { - sct geterror "sum is ${sum}, must be 100" + sct geterror "sum of components is ${sum}, must be 100" error [sct geterror] } %%} @@ -262,7 +277,6 @@ driver knauer_pump = { %%} 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 cmd "REMOTE" sct this_state 1 @@ -283,20 +297,25 @@ driver knauer_pump = { 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 + set saveState ${nextState} + set nextState "noResponse" if { [sct this_state] == 1 } { - set cmd "TT_LOAD:1" + set cmd "GLP?" + set nextState ${saveState} 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" + set cmd "TT_LOAD:1" 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" + 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] == 4 } { - set cmd "TT_SET:2,${time_2},0,${ratio_tgt},0,0,0,0,0,0,0,0" + 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] == 5 } { + 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] == 6 } { set cmd "START:1,0" sct this_state 0 } elseif { [sct this_state] == 91 } { @@ -304,6 +323,13 @@ driver knauer_pump = { sct this_state 92 } elseif { [sct this_state] == 92 } { set cmd "STOP:0,0" + sct this_state 93 + } elseif { [sct this_state] == 93 } { + if { !([hpropexists ${tc_root}/pump/remote target] && [hgetpropval ${tc_root}/pump/remote target] == 1) } { + set cmd "LOCAL" + } else { + set cmd "@@NOSEND@@" + } sct this_state 0 } else { sct this_state 0 @@ -331,6 +357,25 @@ driver knauer_pump = { } %%} + code volume_store = {%% + if { [sct this_state] == 2 } { + set ns [namespace current] + # store the GLP result + hsetprop ${tc_root}/dummy/glp result "${data}" + sct with ${tc_root}/dummy/glp "${ns}::read_glp ${tc_root}" + # extract the volume + sct with ${tc_root}/[sct driveable] "${ns}::volume_fetch ${tc_root} ${nextState} @@NOSEND@@" + sct with ${tc_root}/[sct driveable] "${ns}::volume_read ${tc_root}" + # copy it to base_volume + hsetprop ${tc_root}/[sct driveable] base_volume [hgetpropval ${tc_root}/[sct driveable] raw_volume] + } + if { [hpropexists [sct] target] } { + set data [sct target] + } else { + set data 0.0 + } + %%} + code volume_halt = {%% set cmd "STOP:0,0" sct this_state 91 diff --git a/site_ansto/instrument/config/environment/sct_knauer_pump.tcl b/site_ansto/instrument/config/environment/sct_knauer_pump.tcl index 32f1d88c..1f269659 100644 --- a/site_ansto/instrument/config/environment/sct_knauer_pump.tcl +++ b/site_ansto/instrument/config/environment/sct_knauer_pump.tcl @@ -202,9 +202,21 @@ proc ::scobj::knauer_pump::ratio_check {tc_root} { 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]] + set sum 0 + for {set i 0} {$i < 4} {incr i} { + set cmp [lindex ${rlist} ${i}] + if { ![string is integer -strict ${cmp}] } { + sct geterror "component [expr {${i} + 1}] is not integer: \"${cmp}\"" + error [sct geterror] + } + if { !(${cmp} >= 0 && ${cmp} <= 100) } { + sct geterror "component [expr {${i} + 1}] is not between 0 and 100: \"${cmp}\"" + error [sct geterror] + } + set sum [expr {${sum} + ${cmp}}] + } if { ${sum} != 100 } { - sct geterror "sum is ${sum}, must be 100" + sct geterror "sum of components is ${sum}, must be 100" error [sct geterror] } # ratio_check hook code ends @@ -555,6 +567,16 @@ proc ::scobj::knauer_pump::status_fetch {tc_root nextState cmd_str} { handle_exception ${catch_status} ${catch_message} } +# function to check the write parameter on a device +proc ::scobj::knauer_pump::volume_check {tc_root} { + set catch_status [ catch { + debug_log ${tc_root} 1 "volume_check tc_root=${tc_root} sct=[sct] resp=[sct result]" +# volume_check hook code goes here + return "idle" + } catch_message ] + handle_exception ${catch_status} ${catch_message} +} + # checkstatus function for driveable interface proc ::scobj::knauer_pump::volume_checkstatus {tc_root} { set catch_status [ catch { @@ -644,20 +666,25 @@ proc ::scobj::knauer_pump::volume_fsm {tc_root nextState cmd_str} { 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 + set saveState ${nextState} + set nextState "noResponse" if { [sct this_state] == 1 } { - set cmd "TT_LOAD:1" + set cmd "GLP?" + set nextState ${saveState} 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" + set cmd "TT_LOAD:1" 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" + 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] == 4 } { - set cmd "TT_SET:2,${time_2},0,${ratio_tgt},0,0,0,0,0,0,0,0" + 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] == 5 } { + 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] == 6 } { set cmd "START:1,0" sct this_state 0 } elseif { [sct this_state] == 91 } { @@ -665,6 +692,13 @@ proc ::scobj::knauer_pump::volume_fsm {tc_root nextState cmd_str} { sct this_state 92 } elseif { [sct this_state] == 92 } { set cmd "STOP:0,0" + sct this_state 93 + } elseif { [sct this_state] == 93 } { + if { !([hpropexists ${tc_root}/pump/remote target] && [hgetpropval ${tc_root}/pump/remote target] == 1) } { + set cmd "LOCAL" + } else { + set cmd "@@NOSEND@@" + } sct this_state 0 } else { sct this_state 0 @@ -721,6 +755,79 @@ proc ::scobj::knauer_pump::volume_halt {tc_root} { handle_exception ${catch_status} ${catch_message} } +# function to parse the read of a parameter on a device +proc ::scobj::knauer_pump::volume_read {tc_root} { + set catch_status [ catch { + debug_log ${tc_root} 1 "volume_read tc_root=${tc_root} sct=[sct] result=[sct result]" + if { [hpropexists [sct] geterror] } { + hdelprop [sct] geterror + } + set data [sct result] + set nextState "idle" + if {[string equal -nocase -length 7 ${data} "ASCERR:"]} { + # the protocol driver has reported an error + sct geterror "${data}" + error "[sct geterror]" + } +# volume_read hook code goes here + 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 + } + return ${nextState} + } catch_message ] + handle_exception ${catch_status} ${catch_message} +} + +# function to parse the read of a parameter on a device +proc ::scobj::knauer_pump::volume_store {tc_root} { + set catch_status [ catch { + debug_log ${tc_root} 1 "volume_store tc_root=${tc_root} sct=[sct] result=[sct result]" + if { [hpropexists [sct] geterror] } { + hdelprop [sct] geterror + } + set data [sct result] + set nextState "idle" + if {[string equal -nocase -length 7 ${data} "ASCERR:"]} { + # the protocol driver has reported an error + sct geterror "${data}" + error "[sct geterror]" + } +# volume_store hook code starts + if { [sct this_state] == 2 } { + set ns [namespace current] + # store the GLP result + hsetprop ${tc_root}/dummy/glp result "${data}" + sct with ${tc_root}/dummy/glp "${ns}::read_glp ${tc_root}" + # extract the volume + sct with ${tc_root}/[sct driveable] "${ns}::volume_fetch ${tc_root} ${nextState} @@NOSEND@@" + sct with ${tc_root}/[sct driveable] "${ns}::volume_read ${tc_root}" + # copy it to base_volume + hsetprop ${tc_root}/[sct driveable] base_volume [hgetpropval ${tc_root}/[sct driveable] raw_volume] + } + if { [hpropexists [sct] target] } { + set data [sct target] + } else { + set data 0.0 + } +# volume_store hook code ends + if { [hpropexists [sct] geterror] } { + debug_log ${tc_root} 9 "[sct] error: [sct geterror]" + error "[sct geterror]" + } + 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 + } + return ${nextState} + } catch_message ] + handle_exception ${catch_status} ${catch_message} +} + # function to write a parameter value on a device proc ::scobj::knauer_pump::volume_write {tc_root nextState cmd_str} { set catch_status [ catch { @@ -731,7 +838,6 @@ proc ::scobj::knauer_pump::volume_write {tc_root nextState cmd_str} { set par [sct target] set cmd "${cmd_str}${par}" # volume_write hook code starts - 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 @@ -961,8 +1067,8 @@ proc ::scobj::knauer_pump::mkDriver { sct_controller name device_class simulatio hsetprop ${scobj_hpath}/pump/volume type "part" hfactory ${scobj_hpath}/pump/volume/pval plain user float - hsetprop ${scobj_hpath}/pump/volume/pval read ${ns}::volume_fetch ${scobj_hpath} rdValue { } - hsetprop ${scobj_hpath}/pump/volume/pval rdValue ${ns}::rdValue ${scobj_hpath} + hsetprop ${scobj_hpath}/pump/volume/pval read ${ns}::volume_fetch ${scobj_hpath} volume_read { } + hsetprop ${scobj_hpath}/pump/volume/pval volume_read ${ns}::volume_read ${scobj_hpath} hsetprop ${scobj_hpath}/pump/volume/pval control true hsetprop ${scobj_hpath}/pump/volume/pval data true hsetprop ${scobj_hpath}/pump/volume/pval mutable true @@ -975,10 +1081,10 @@ proc ::scobj::knauer_pump::mkDriver { sct_controller name device_class simulatio hsetprop ${scobj_hpath}/pump/volume/pval nxalias "${name}_pump_volume_pval" hfactory ${scobj_hpath}/pump/volume/setp plain user float - hsetprop ${scobj_hpath}/pump/volume/setp read ${ns}::volume_fsm ${scobj_hpath} rdValue { } - hsetprop ${scobj_hpath}/pump/volume/setp rdValue ${ns}::rdValue ${scobj_hpath} - hsetprop ${scobj_hpath}/pump/volume/setp write ${ns}::volume_write ${scobj_hpath} noResponse { } - hsetprop ${scobj_hpath}/pump/volume/setp noResponse ${ns}::noResponse ${scobj_hpath} + hsetprop ${scobj_hpath}/pump/volume/setp read ${ns}::volume_fsm ${scobj_hpath} volume_store { } + hsetprop ${scobj_hpath}/pump/volume/setp volume_store ${ns}::volume_store ${scobj_hpath} + hsetprop ${scobj_hpath}/pump/volume/setp write ${ns}::volume_write ${scobj_hpath} volume_check { } + hsetprop ${scobj_hpath}/pump/volume/setp volume_check ${ns}::volume_check ${scobj_hpath} hsetprop ${scobj_hpath}/pump/volume/setp check ${ns}::checkrange ${scobj_hpath} hsetprop ${scobj_hpath}/pump/volume/setp driving 0 hsetprop ${scobj_hpath}/pump/volume/setp checklimits ${ns}::checklimits ${scobj_hpath} @@ -1014,7 +1120,7 @@ proc ::scobj::knauer_pump::mkDriver { sct_controller name device_class simulatio ansto_makesctdrive ${name}_pump_volume_setp ${scobj_hpath}/pump/volume/setp ${scobj_hpath}/pump/volume/pval ${sct_controller} } # mkDriver hook code starts - hset ${scobj_hpath}/pump/remote 1 + #hset ${scobj_hpath}/pump/remote 1 # mkDriver hook code ends } catch_message ] handle_exception ${catch_status} ${catch_message}