365 lines
10 KiB
Plaintext
365 lines
10 KiB
Plaintext
#
|
|
# Simple driver generator for the Hiden Isochema XCS vapour delivery system
|
|
# vim: ts=8 sts=2 sw=2 expandtab autoindent smartindent nocindent
|
|
#
|
|
driver hiden_xcs = {
|
|
# driver_property douglas = clowes
|
|
vendor = hiden; device = xcs; protocol = std;
|
|
class = environment
|
|
simulation_group = environment_simulation
|
|
add_args = 'id'
|
|
make_args = 'id'
|
|
#
|
|
# Unnamed group has variables at device level
|
|
#
|
|
group = {
|
|
# group_property douglas = clowes
|
|
type = float
|
|
priv = user
|
|
group_property 'data' = 'true'
|
|
group_property 'nxsave' = 'true'
|
|
property 'klass' = 'environment'
|
|
property 'sdsinfo' = '::nexus::scobj::sdsinfo'
|
|
var auto = {
|
|
type = int;
|
|
allowed = '0,1';
|
|
value = 0;
|
|
}
|
|
var enabled = {
|
|
permlink = 'G.X02'
|
|
type = int;
|
|
priv = user;
|
|
readable = 10;
|
|
writeable = 1;
|
|
read_function = read_digital;
|
|
write_Function = write_digital;
|
|
read_command = '?DOUT,2';
|
|
write_command = '!DOUT,2,';
|
|
allowed = '0,1';
|
|
readable = 10;
|
|
# property junk = junk;
|
|
}
|
|
var gas_factor = { value = 1.0; }
|
|
control = false
|
|
data = false
|
|
nxsave = false
|
|
var temperature
|
|
var flow1
|
|
var flow2
|
|
var flow3
|
|
}
|
|
#
|
|
# The named group is at the device level, variables below that
|
|
#
|
|
group flow = {
|
|
type = float
|
|
mutable = true
|
|
priv = user
|
|
group_property 'data' = 'true'
|
|
group_property 'nxsave' = 'true'
|
|
property 'klass' = 'environment'
|
|
property 'sdsinfo' = '::nexus::scobj::sdsinfo'
|
|
var sensor = {
|
|
permlink = 'G.S01'
|
|
readable = 1
|
|
read_command = 'None'
|
|
fetch_function = fetch_flow
|
|
read_function = read_flow
|
|
pid_function = pid_flow
|
|
property pid_error = 0
|
|
property pid_deriv = 0
|
|
property pid_integ = 0
|
|
property pid_pvalue = 0.1
|
|
property pid_ivalue = 0.1
|
|
property pid_dvalue = 0.0
|
|
property pid_imax = 50
|
|
}
|
|
var setpoint = {
|
|
readable = 1;
|
|
read_command = '@'
|
|
fetch_function = getTarget
|
|
permlink = 'G.SP01'
|
|
driveable = flow/sensor
|
|
write_function = write_flow
|
|
value = 100
|
|
lowerlimit = 0
|
|
upperlimit = 500
|
|
tolerance = 1
|
|
}
|
|
}
|
|
group humidity = {
|
|
type = float
|
|
mutable = true
|
|
priv = user
|
|
group_property 'data' = 'true'
|
|
group_property 'nxsave' = 'true'
|
|
property 'klass' = 'environment'
|
|
property 'sdsinfo' = '::nexus::scobj::sdsinfo'
|
|
var sensor = {
|
|
permlink = 'G.S02'
|
|
readable = 1
|
|
read_command = '?ALL DATA'
|
|
read_function = read_all_data
|
|
pid_function = pid_humidity
|
|
property pid_error = 0
|
|
property pid_deriv = 0
|
|
property pid_integ = 0
|
|
property pid_pvalue = 1.0
|
|
property pid_ivalue = 0.10
|
|
property pid_dvalue = 0.0
|
|
property pid_imax = 20
|
|
}
|
|
var setpoint = {
|
|
readable = 1;
|
|
read_command = '@'
|
|
fetch_function = getTarget
|
|
permlink = 'G.SP02'
|
|
driveable = humidity/sensor
|
|
write_function = write_humidity
|
|
checkrange_function = chkrange_function
|
|
value = 50
|
|
lowerlimit = 0
|
|
upperlimit = 100
|
|
tolerance = 1
|
|
}
|
|
}
|
|
group analog = {
|
|
# group_property 'data' = true
|
|
type = float;
|
|
priv = user;
|
|
control = false
|
|
data = false
|
|
nxsave = false
|
|
readable = 5;
|
|
read_function = read_sixteen;
|
|
property base = 0; # applies to all following vars
|
|
var pv1 = { read_command = '?AIN,0'; property span = 500; }; # ain0
|
|
var pv2 = { read_command = '?AIN,1'; property span = 500; }; # ain1
|
|
var pv3 = { read_command = '?AIN,2'; property span = 500; }; # ain2
|
|
var rhtemp = { read_command = '?AIN,8'; property span = 100; }; # ain8
|
|
var rhsense = { read_command = '?AIN,9'; property span = 100; }; # ain9
|
|
var ansto_temp = { read_command = '?AIN,12'; property span = 100; }; # ain12
|
|
writeable = 1;
|
|
read_function = read_twelve;
|
|
write_function = write_twelve;
|
|
var sp1 = { read_command = '?AOUT,0'; write_command = '!AOUT,0,'; property span = 500; } # aout0
|
|
var sp2 = { read_command = '?AOUT,1'; write_command = '!AOUT,1,'; property span = 500; } # aout1
|
|
var sp3 = { read_command = '?AOUT,2'; write_command = '!AOUT,2,'; property span = 500; } # aout2
|
|
};
|
|
|
|
#
|
|
# Code lines start with '@' which is stripped before being emitted into generated driver
|
|
# The code is emitted at the appropriate place in the given function
|
|
#
|
|
code getTarget = {
|
|
@ if { [hpropexists [sct] target] } {
|
|
@ sct result [sct target]
|
|
@ } else {
|
|
@ sct result [hval [sct]]
|
|
@ }
|
|
@ set cmd "@@NOSEND@@"
|
|
}
|
|
code read_function read_digital = {
|
|
@ if { [string equal -nocase -length 5 "${data}" "DOUT ="] } {
|
|
@ set result [scan "${data}" "DOUT = %d OK" val]
|
|
@ if { ${result} == 1 } {
|
|
@ set data ${val}
|
|
@ } else {
|
|
@ sct geterror "Syntax error (Result=${result}) in: '${data}'"
|
|
@ }
|
|
@ } else {
|
|
@ sct geterror "Syntax error in: '${data}'"
|
|
@ }
|
|
}
|
|
|
|
code read_function read_twelve = {
|
|
@ if { [string equal -nocase -length 5 "${data}" "AOUT ="] } {
|
|
@ set result [scan "${data}" "AOUT = %d OK" val]
|
|
@ if { ${result} == 1 } {
|
|
@ if { [hpropexists [sct] base] } {
|
|
@ set base [sct base]
|
|
@ } else {
|
|
@ set base 0.0
|
|
@ }
|
|
@ if { [hpropexists [sct] span] } {
|
|
@ set span [sct span]
|
|
@ } else {
|
|
@ set span 500.0
|
|
@ }
|
|
@ set data [expr (${span} * (${val} - ${base})) / 4095.0]
|
|
@ } else {
|
|
@ sct geterror "Syntax (Result=${result}) error in: '${data}'"
|
|
@ }
|
|
@ } else {
|
|
@ sct geterror "Syntax error in: '${data}'"
|
|
@ }
|
|
}
|
|
|
|
code read_function read_sixteen = {
|
|
@ if { [string equal -nocase -length 5 "${data}" "AIN ="] } {
|
|
@ set result [scan "${data}" "AIN = %d OK" val]
|
|
@ if { ${result} == 1 } {
|
|
@ if { [hpropexists [sct] base] } {
|
|
@ set base [sct base]
|
|
@ } else {
|
|
@ set base 0.0
|
|
@ }
|
|
@ if { [hpropexists [sct] span] } {
|
|
@ set span [sct span]
|
|
@ } else {
|
|
@ set span 500.0
|
|
@ }
|
|
@ set data [expr (${span} * (${val} - ${base})) / 65535.0]
|
|
@ } else {
|
|
@ sct geterror "Syntax error (Result=${result}) in: '${data}'"
|
|
@ }
|
|
@ } else {
|
|
@ sct geterror "Syntax error in: '${data}'"
|
|
@ }
|
|
}
|
|
|
|
code read_function read_all_data = {
|
|
@ if { [string equal -nocase -length 2 "${data}" "A "] } {
|
|
@ set data_list [split [string range "${data}" 2 end-3] ',']
|
|
@ if { [llength ${data_list}] == 8 } {
|
|
@ set data [expr [lindex ${data_list} 0]]
|
|
@ hupdate ${tc_root}/temperature [expr [lindex ${data_list} 1]]
|
|
@ hupdate ${tc_root}/flow1 [expr [lindex ${data_list} 3] / [hval ${tc_root}/gas_factor]]
|
|
@ hupdate ${tc_root}/flow2 [expr [lindex ${data_list} 4] / [hval ${tc_root}/gas_factor]]
|
|
@ hupdate ${tc_root}/flow3 [expr [lindex ${data_list} 5] / [hval ${tc_root}/gas_factor]]
|
|
@ } else {
|
|
@ sct geterror "Syntax error (not 8) for read_all_data in: '${data}'"
|
|
@ }
|
|
@ } else {
|
|
@ sct geterror "Syntax error (not A) for read_all_data in: '${data}'"
|
|
@ }
|
|
@ set sp [pathname [sct]]/setpoint
|
|
@ if { [hpropexists ${sp} target] } {
|
|
@ set sp [hgetpropval ${sp} target]
|
|
@ pid_humidity ${tc_root} ${sp} ${data}
|
|
@ }
|
|
}
|
|
|
|
code pid_function pid_humidity = {
|
|
@ if { ![hval ${tc_root}/auto] } {
|
|
@ set pid 0.0
|
|
@ sct pid_integ 0.0
|
|
@ }
|
|
@ set sign 1
|
|
@ foreach node [list ${tc_root}/analog/sp1 ${tc_root}/analog/sp2] {
|
|
@ set sign [expr -${sign}]
|
|
@ set signed_pid [expr ${sign} * ${pid}]
|
|
@ if { !([hpropexists ${node} bias_humidity] && [hgetpropval ${node} bias_humidity] == ${signed_pid}) } {
|
|
@ hsetprop ${node} bias_humidity ${signed_pid}
|
|
@ if { [hpropexists ${node} target] } {
|
|
@ hset ${node} [hgetpropval ${node} target]
|
|
@ } else {
|
|
@ hset ${node} [hval ${node}]
|
|
@ }
|
|
@ }
|
|
@ }
|
|
}
|
|
|
|
code fetch_function fetch_flow = {
|
|
@ set data 0.0
|
|
@ foreach node [list flow1 flow2] {
|
|
@ set data [expr ${data} + [hval ${tc_root}/${node}]]
|
|
@ }
|
|
@ sct result ${data}
|
|
@ set sp [pathname [sct]]/setpoint
|
|
@ if { [hpropexists ${sp} target] } {
|
|
@ set sp [hgetpropval ${sp} target]
|
|
@ pid_flow ${tc_root} ${sp} ${data}
|
|
@ }
|
|
@ set cmd "@@NOSEND@@"
|
|
}
|
|
|
|
code pid_function pid_flow = {
|
|
@ if { ![hval ${tc_root}/auto] } {
|
|
@ set pid 0.0
|
|
@ sct pid_integ 0.0
|
|
@ }
|
|
@ foreach node [list ${tc_root}/analog/sp1 ${tc_root}/analog/sp2] {
|
|
@ if { !([hpropexists ${node} bias_flow] && [hgetpropval ${node} bias_flow] == ${pid}) } {
|
|
@ hsetprop ${node} bias_flow ${pid}
|
|
@ if { [hpropexists ${node} target] } {
|
|
@ hset ${node} [hgetpropval ${node} target]
|
|
@ } else {
|
|
@ hset ${node} [hval ${node}]
|
|
@ }
|
|
@ }
|
|
@ }
|
|
}
|
|
|
|
code write_function write_digital = {
|
|
}
|
|
|
|
code write_function write_twelve = {
|
|
@ if { [hpropexists [sct] base] } {
|
|
@ set base [sct base]
|
|
@ } else {
|
|
@ set base 0.0
|
|
@ }
|
|
@ if { [hpropexists [sct] span] } {
|
|
@ set span [sct span]
|
|
@ } else {
|
|
@ set span 500.0
|
|
@ }
|
|
@ if { [hpropexists [sct] bias_humidity] } {
|
|
@ set par [expr ${par} + [sct bias_humidity]]
|
|
@ }
|
|
@ if { [hpropexists [sct] bias_flow] } {
|
|
@ set par [expr ${par} + [sct bias_flow]]
|
|
@ }
|
|
@ if { ${par} < 0.0 } {
|
|
@ set par 0.0
|
|
@ }
|
|
@ if { ${par} > ${span} } {
|
|
@ set par ${span}
|
|
@ }
|
|
@ set par [expr int(${base} + (4095.0 * ${par} / ${span}))]
|
|
@ set cmd "${cmd_str}${par}"
|
|
}
|
|
|
|
code write_function write_flow = {
|
|
@ if { [hpropexists ${tc_root}/humidity/setpoint target] } {
|
|
@ set humidity_target [hgetpropval ${tc_root}/humidity/setpoint target]
|
|
@ } else {
|
|
@ set humidity_target [hval ${tc_root}/humidity/setpoint]
|
|
@ }
|
|
@ set flow1_target [expr (0.01 * (100.0 - ${humidity_target})) * [sct target]]
|
|
@ set flow2_target [expr (0.01 * ( ${humidity_target})) * [sct target]]
|
|
@ hset ${tc_root}/analog/sp1 ${flow1_target}
|
|
@ hset ${tc_root}/analog/sp2 ${flow2_target}
|
|
@ set nextState "idle"
|
|
@ set cmd "@@NOSEND@@"
|
|
}
|
|
|
|
code write_function write_humidity = {
|
|
@ if { [hpropexists ${tc_root}/flow/setpoint target] } {
|
|
@ set flow_target [hgetpropval ${tc_root}/flow/setpoint target]
|
|
@ } else {
|
|
@ set flow_target [hval ${tc_root}/flow/setpoint]
|
|
@ }
|
|
@ set flow1_target [expr (0.01 * (100.0 - [sct target])) * ${flow_target}]
|
|
@ set flow2_target [expr (0.01 * ( [sct target])) * ${flow_target}]
|
|
@ hset ${tc_root}/analog/sp1 ${flow1_target}
|
|
@ hset ${tc_root}/analog/sp2 ${flow2_target}
|
|
@ set nextState "idle"
|
|
@ set cmd "@@NOSEND@@"
|
|
}
|
|
|
|
code write_function no_op = {
|
|
@ set cmd "@@NOSEND@@"
|
|
}
|
|
#
|
|
# This code is after database creation
|
|
#
|
|
code mkDriver = {
|
|
}
|
|
|
|
code chkrange_function = {
|
|
@ # hooked
|
|
}
|
|
};
|