Better checks and state machine for Knauer pump
This commit is contained in:
@ -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
|
||||
|
@ -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}
|
||||
|
Reference in New Issue
Block a user