diff --git a/SICSmain.c b/SICSmain.c index c069629d..e6df767b 100644 --- a/SICSmain.c +++ b/SICSmain.c @@ -33,6 +33,10 @@ #define DEFAULTINIFILE "servo.tcl" +int usage(const char* name) { + fprintf(stderr, "usage: %s [-d] [-nolog] \n", name); + return 1; +} /*--------------------------------------------------------------------------- The Servers Main program. May take one argument: the name of an initialisation file @@ -45,6 +49,9 @@ char *file=NULL; int i, firstArg=1; + if (argc < 2) + return usage(argv[0]); + /* initialise, will die on you if problems */ if (strcasecmp(argv[1], "-d") == 0) { debug = 1; @@ -57,6 +64,10 @@ file = argv[i]; } } + + if (file == NULL) + return usage(argv[0]); + iRet = InitServer(file,&pServ); if(!iRet) { diff --git a/site_ansto/hardsup/sct_oxfordprot.c b/site_ansto/hardsup/sct_oxfordprot.c new file mode 100644 index 00000000..057fbc78 --- /dev/null +++ b/site_ansto/hardsup/sct_oxfordprot.c @@ -0,0 +1,110 @@ +/** @file Oxford protocol handler for script-context based controllers. +* +* If you 'send' commands to a oxford controller using this protocol you +* will get one of three possible responses, +* 1. A value +* eg +* 2. An acknowledgement (ie 'OK') +* eg +* sct_mc2 send "MOG" +* OK +* 3. An error message +* eg +* sct_mc2 send "BGG" +* ASCERR: 20 Begin not valid with motor off (during read finished) +*/ +#include +#include +#include +#include + +/** @brief Set line terminator before sending command +*/ +int OxfordWriteStart(Ascon *a) { + DynStringConcat(a->wrBuffer,"\r"); + a->state = AsconWriting; + a->wrPos = 0; + return 1; +} + +/** @brief Map oxford replies to OK, ASCERR:..., value. +* You can use the first character to sort replies from a oxford controller +* into four categories +* First character is, +* 'SPACE' This is followed by a value +* '?' Error, use 'TC 1' to get error code and message. +* ':' Command received, in response to commands which don't request data. +* '1-9' First digit of error-code followed by error message. (in response to 'TC 1') +*/ +int OxfordReading(Ascon *a) { + int ret; + char chr, ch[2]; + char* cp = NULL; + + ret = AsconReadChar(a->fd, &chr); + while (ret > 0) { + if (chr != '\r') { + DynStringConcatChar(a->rdBuffer, chr); + ret = AsconReadChar(a->fd, &chr); + } + else { + cp = GetCharArray(a->rdBuffer); + chr = *cp; + if (*cp == '?') { /* command was in error */ + a->state = AsconIdle; +#if 0 + AsconError(a, GetCharArray(a->rdBuffer), 0); +#else + DynStringInsert(a->rdBuffer, "ASCERR:", 0); +#endif + return 0; + } + else if (GetDynStringLength(a->rdBuffer) == 1) { /* command was successful */ + DynStringReplace(a->rdBuffer, "OK", 0); + a->state = AsconReadDone; + return 1; + } + else { + a->state = AsconReadDone; + return 1; + } + } + } + return 1; +} + +/** brief Oxford protocol handler. +* This handler formats commands (ie adds cr line terminator) and +* sorts replies into standard responses of +* +* OK +* ASCERR:... +*/ +int OxfordProtHandler(Ascon *a) { + int ret; + + switch(a->state){ + case AsconWriteStart: + ret = OxfordWriteStart(a); + return ret; + break; + case AsconReading: + ret = OxfordReading(a); + return ret; + break; + default: + ret = AsconStdHandler(a); + return ret; + } + return 1; +} + +void AddOxfordProtocoll(){ + AsconProtocol *prot = NULL; + + prot = calloc(sizeof(AsconProtocol), 1); + prot->name = strdup("oxford"); + prot->init = AsconStdInit; + prot->handler = OxfordProtHandler; + AsconInsertProtocol(prot); +} diff --git a/site_ansto/instrument/config/environment/temperature/sct_oxford_500.tcl b/site_ansto/instrument/config/environment/temperature/sct_oxford_500.tcl new file mode 100644 index 00000000..22774566 --- /dev/null +++ b/site_ansto/instrument/config/environment/temperature/sct_oxford_500.tcl @@ -0,0 +1,519 @@ +# Define procs in ::scobj::xxx namespace +# MakeSICSObj $obj SCT_ +# The MakeSICSObj cmd adds a /sics/$obj node. NOTE the /sics node is not browsable. + + +namespace eval ::scobj::itc500 { +# Temperature controllers must have at least the following nodes +# /tempcont/setpoint +# /tempcont/sensor/value + proc debug_log {args} { + set fd [open "/tmp/itc500.log" a] + puts $fd $args + close $fd + } + + proc getValue {nextState cmd} { + sct send $cmd + return $nextState + } + proc setValue {nextState cmd} { + set par [expr int(18 * [sct target])] + sct send "$cmd $par" +debug_log "setValue $cmd $par" + return $nextState + } + + proc setPoint {tc_root nextState cmd} { + set my_model "[SplitReply [hgetprop $tc_root/itc500_state my_model]]" + if {$my_model == "ITC502"} { + set par [expr int(10 * [sct target])] + } else { + set par "[sct target]" + } + hset $tc_root/status "busy" + if {[sct writestatus] == "start"} { + # Called by drive adapter + hsetprop $tc_root/setpoint driving 1 + } + sct send "$cmd$par" +debug_log "setPoint $cmd$par" + return $nextState + } + + proc rdValue {tc_root} { + set data [sct result] + if [ catch { +debug_log "rdValue $tc_root [sct] result=$data" + } message ] { +debug_log "rdValue $tc_root failure" + } + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + } + default { + set my_model "[SplitReply [hgetprop $tc_root/itc500_state my_model]]" + if {[string index $data 0] == "R"} { + set data [string range $data 1 end] + if {$my_model == "ITC502"} { +debug_log "rdValue $tc_root ITC502-a result=$data" + set rslt [scan $data %d data] + set data [expr $data / 10.0] +debug_log "rdValue $tc_root ITC502-b result=$data" + } elseif {$my_model == "ITC503"} { +debug_log "rdValue $tc_root ITC503-a result=$data" + set rslt [scan $data %f data] +debug_log "rdValue $tc_root ITC503-b result=$data" + } + if {$data != [sct oldval]} { + sct oldval $data + sct update $data + sct utime readtime +debug_log "rdValue new data for $tc_root [sct] $my_model result=$data" + } + } else { + sct geterror "SYNERR:$data" + } + } + } + return idle + } + + proc getState {tc_root nextState cmd} { + set my_state "[SplitReply [hgetprop $tc_root/itc500_state my_state]]" + if {$my_state == "STATE_V"} { + set my_cmd "V" + } elseif {$my_state == "STATE_X"} { + set my_cmd "X" + } elseif {$my_state == "STATE_C"} { + set my_cmd "C1" + } elseif {$my_state == "STATE_A0"} { + set my_cmd "A0" + } elseif {$my_state == "STATE_A"} { + set auto 0 + if {[hval $tc_root/heater_auto] > 0} { + set auto [expr $auto + 1] + } + if {[hval $tc_root/cooler_auto] > 0} { + set auto [expr $auto + 2] + } + set my_cmd "A$auto" + } elseif {$my_state == "STATE_H"} { + set my_cmd "H[hval $tc_root/control_sensor]" + } elseif {$my_state == "STATE_T0" || $my_state == "STATE_T"} { + set my_cmd "T[SplitReply [hgetprop $tc_root/setpoint target]]" + } elseif {$my_state == "STATE_F"} { + set my_cmd "F[hval $tc_root/control_sensor]" + } else { + hsetprop $tc_root/itc500_state my_state "STATE_X" + set my_cmd "X" + } + sct send "$my_cmd" +debug_log "getState end $tc_root state=$my_state, cmd=$my_cmd" + return $nextState + } + + proc checktol {tc_root currtime timecheck} { +debug_log "checktol $tc_root $currtime $timecheck" + set temp [hval $tc_root/sensor/value] + set lotemp [expr [$tc_root/setpoint] - [hval $tc_root/tolerance]] + set hitemp [expr [$tc_root/setpoint] + [hval $tc_root/tolerance]] + if { $temp < $lotemp || $temp > $hitemp} { + hset $tc_root/emon/isintol 0 + return 0 + } else { + set timeout [hval $tc_root/tolerance/settletime] + if {[expr $currtime - $timecheck] > $timeout} { + hset $tc_root/emon/isintol 1 + } + return 1 + } + } + + ## + # @brief Reads the current itc500 state and error messages. + proc rdState {tc_root} { + set my_state "[SplitReply [hgetprop $tc_root/itc500_state my_state]]" + set my_model "[SplitReply [hgetprop $tc_root/itc500_state my_model]]" +debug_log "rdState $tc_root state=$my_state, response=[sct result], version=$my_model" + if {$my_state == "STATE_V"} { + set my_version "[sct result]" + hsetprop $tc_root/itc500_state my_version "$my_version" + if {[string range $my_version 0 5] == "ITC502"} { + hsetprop $tc_root/itc500_state my_model "ITC502" + } elseif {[string range $my_version 0 5] == "ITC503"} { + hsetprop $tc_root/itc500_state my_model "ITC503" + } + hsetprop $tc_root/itc500_state my_state "STATE_X" + set my_model "[SplitReply [hgetprop $tc_root/itc500_state my_model]]" +debug_log "rdState $tc_root state=$my_state, version=$my_model" +# return idle + return getState + } elseif {$my_state == "STATE_X"} { + hsetprop $tc_root/itc500_state my_status "[sct result]" + set my_status "[SplitReply [hgetprop $tc_root/itc500_state my_status]]" +debug_log "rdState my_status=$my_status" + set rslt [scan $my_status "X%dA%dC%dS%dH%dL%d" the_x the_a the_c the_s the_h the_l] +debug_log "rdState $tc_root status($rslt)= X$the_x A$the_a C$the_c S[format %02d $the_s] H$the_h L$the_l" + set auto 0 + if {[hval $tc_root/heater_auto] > 0} { + set auto [expr $auto + 1] + } + if {[hval $tc_root/cooler_auto] > 0} { + set auto [expr $auto + 2] + } + if {$the_c != 1} { + hsetprop $tc_root/itc500_state my_state "STATE_C" + } elseif {$the_h != [hval $tc_root/control_sensor]} { + hsetprop $tc_root/itc500_state my_state "STATE_A0" + } elseif {$the_a != $auto} { + hsetprop $tc_root/itc500_state my_state "STATE_A" + } elseif {[hpropexists $tc_root/setpoint target] && [SplitReply [hgetprop $tc_root/setpoint target]] != [hval $tc_root/setpoint]} { + hsetprop $tc_root/itc500_state my_state "STATE_T" + } else { + hsetprop $tc_root/itc500_state my_state "STATE_F" + } + hsetprop $tc_root/control_sensor oldval $the_h + return getState + } elseif {$my_state == "STATE_C"} { + set my_status "[SplitReply [hgetprop $tc_root/itc500_state my_status]]" + set rslt [scan $my_status "X%dA%dC%dS%dH%dL%d" the_x the_a the_c the_s the_h the_l] + set auto 0 + if {[hval $tc_root/heater_auto] > 0} { + set auto [expr $auto + 1] + } + if {[hval $tc_root/cooler_auto] > 0} { + set auto [expr $auto + 2] + } + if {[hval $tc_root/control_sensor] != $the_h} { + hsetprop $tc_root/itc500_state my_state "STATE_A0" + } elseif {$the_a != $auto} { + hsetprop $tc_root/itc500_state my_state "STATE_A" + } elseif {[hpropexists $tc_root/setpoint target] && [SplitReply [hgetprop $tc_root/setpoint target]] != [hval $tc_root/setpoint]} { + hsetprop $tc_root/itc500_state my_state "STATE_T" + } else { + hsetprop $tc_root/itc500_state my_state "STATE_F" + } + return getState + } elseif {$my_state == "STATE_A0"} { + hsetprop $tc_root/itc500_state my_state "STATE_H" + return getState + } elseif {$my_state == "STATE_H"} { + hsetprop $tc_root/itc500_state my_state "STATE_T0" + return getState + } elseif {$my_state == "STATE_T0"} { + hsetprop $tc_root/itc500_state my_state "STATE_A" + return getState + } elseif {$my_state == "STATE_T"} { + hsetprop $tc_root/itc500_state my_state "STATE_F" + return getState + } elseif {$my_state == "STATE_A"} { + hsetprop $tc_root/itc500_state my_state "STATE_F" + return getState + } elseif {$my_state == "STATE_F"} { + hsetprop $tc_root/itc500_state my_state "STATE_X" + } else { + hsetprop $tc_root/itc500_state my_state "STATE_X" + } + set my_status "[SplitReply [hgetprop $tc_root/itc500_state my_status]]" +debug_log "rdState my_status=$my_status" + set rslt [scan $my_status "X%dA%dC%dS%dH%dL%d" the_x the_a the_c the_s the_h the_l] +debug_log "rdState $tc_root status($rslt)= X$the_x A$the_a C$the_c S[format %02d $the_s] H$the_h L$the_l" + set my_driving [SplitReply [hgetprop $tc_root/setpoint driving]] +debug_log "rdState $tc_root: driving=$my_driving" + if [ catch { + set val "[hval $tc_root/setpoint]" + } message ] { + set val 0 +debug_log "rdState $tc_root: setpoint=failure" + } +debug_log "rdState $tc_root: setpoint=$val" + if {[hpropexists $tc_root/setpoint target]} { + set tgt [SplitReply [hgetprop $tc_root/setpoint target]] +debug_log "rdState $tc_root: target=$tgt" + } else { + hsetprop $tc_root/setpoint target $val + set tgt [SplitReply [hgetprop $tc_root/setpoint target]] +debug_log "rdState $tc_root: initialised target to: target=$tgt" + } + if {$my_driving > 0} { + if {[hval $tc_root/control_sensor] == "3"} { + set temp [hval $tc_root/sensor3/value] + } elseif {[hval $tc_root/control_sensor] == "2"} { + set temp [hval $tc_root/sensor2/value] + } else { + set temp [hval $tc_root/sensor/value] + } + set tol [hval $tc_root/tolerance] + set lotemp [expr $tgt - $tol] + set hitemp [expr $tgt + $tol] +debug_log "rdState driving $tc_root until $temp in ($lotemp, $hitemp)" + if {$temp < $lotemp} { + } elseif {$temp > $hitemp} { + } else { + hset $tc_root/status "idle" + hsetprop $tc_root/setpoint driving 0 +debug_log "rdState driving $tc_root finished at $temp in ($lotemp, $hitemp)" + } + } + return idle + } + + proc noResponse {} { + return idle + } + proc wrtValue {wcmd args} { + } + + proc check {tc_root} { + set setpoint [sct target] + set lolimit [hval $tc_root/lowerlimit] + set hilimit [hval $tc_root/upperlimit] + if {$setpoint < $lolimit || $setpoint > $hilimit} { + error "setpoint violates limits" + } + return OK + } + +## +# @brief Implement the checkstatus command for the drivable interface +# +# NOTE: The drive adapter initially sets the writestatus to "start" and will +# only call this when writestatus!="start" + proc drivestatus {tc_root} { + if [sct driving] { + return busy + } else { + return idle + } + } + + proc halt {tc_root} { +debug_log "halt $tc_root" + hset $tc_root/setpoint [hval $tc_root/sensor/value] + hsetprop $tc_root/setpoint driving 0 + return idle + } + + proc mk_sct_oxford_itc500 {sct_controller klass tempobj tol} { + if [ catch { + set ns ::scobj::itc500 + + MakeSICSObj $tempobj SCT_OBJECT + sicslist setatt $tempobj klass $klass + sicslist setatt $tempobj long_name $tempobj + + set scobj_hpath /sics/$tempobj + hfactory $scobj_hpath/setpoint plain user float + hsetprop $scobj_hpath/setpoint read ${ns}::getValue rdValue "R0" + hsetprop $scobj_hpath/setpoint write ${ns}::setPoint $scobj_hpath noResponse "T" + hsetprop $scobj_hpath/setpoint check ${ns}::check $scobj_hpath + hsetprop $scobj_hpath/setpoint rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/setpoint noResponse ${ns}::noResponse + hsetprop $scobj_hpath/setpoint oldval UNKNOWN + hsetprop $scobj_hpath/setpoint driving 0 + hsetprop $scobj_hpath/setpoint writestatus UNKNOWN + # Drive adapter interface + hsetprop $scobj_hpath/setpoint checklimits ${ns}::check $scobj_hpath + hsetprop $scobj_hpath/setpoint checkstatus ${ns}::drivestatus $scobj_hpath + hsetprop $scobj_hpath/setpoint halt ${ns}::halt $scobj_hpath + + hfactory $scobj_hpath/sensor plain spy none + hfactory $scobj_hpath/sensor/value plain internal float + hsetprop $scobj_hpath/sensor/value read ${ns}::getValue rdValue "R1" + hsetprop $scobj_hpath/sensor/value rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/sensor/value oldval UNKNOWN + hsetprop $scobj_hpath/sensor/value lowerlimit 1.5 + hsetprop $scobj_hpath/sensor/value upperlimit 250 + hsetprop $scobj_hpath/sensor/value units "K" + + hfactory $scobj_hpath/sensor2 plain spy none + hfactory $scobj_hpath/sensor2/value plain internal float + hsetprop $scobj_hpath/sensor2/value read ${ns}::getValue rdValue "R2" + hsetprop $scobj_hpath/sensor2/value rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/sensor2/value oldval UNKNOWN + hsetprop $scobj_hpath/sensor2/value lowerlimit 0.25 + hsetprop $scobj_hpath/sensor2/value upperlimit 7 + hsetprop $scobj_hpath/sensor2/value units "K" + + hfactory $scobj_hpath/sensor3 plain spy none + hfactory $scobj_hpath/sensor3/value plain internal float + hsetprop $scobj_hpath/sensor3/value read ${ns}::getValue rdValue "R3" + hsetprop $scobj_hpath/sensor3/value rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/sensor3/value oldval UNKNOWN + hsetprop $scobj_hpath/sensor3/value lowerlimit 1.0 + hsetprop $scobj_hpath/sensor3/value upperlimit 300 + hsetprop $scobj_hpath/sensor3/value units "K" + + hfactory $scobj_hpath/heating_power_percent plain internal float + hsetprop $scobj_hpath/heating_power_percent read ${ns}::getValue rdValue "R5" + hsetprop $scobj_hpath/heating_power_percent rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/heating_power_percent oldval UNKNOWN + + hfactory $scobj_hpath/heating_power_volts plain internal float + hsetprop $scobj_hpath/heating_power_volts read ${ns}::getValue rdValue "R6" + hsetprop $scobj_hpath/heating_power_volts rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/heating_power_volts oldval UNKNOWN + + hfactory $scobj_hpath/gas_flow plain internal float + hsetprop $scobj_hpath/gas_flow read ${ns}::getValue rdValue "R7" + hsetprop $scobj_hpath/gas_flow rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/gas_flow oldval UNKNOWN + + hfactory $scobj_hpath/control_sensor plain user int + hsetprop $scobj_hpath/control_sensor values 1,2,3 + hsetprop $scobj_hpath/control_sensor oldval 1 + hset $scobj_hpath/control_sensor 1 + + hfactory $scobj_hpath/heater_auto plain user int + hsetprop $scobj_hpath/heater_auto values 0,1 + hsetprop $scobj_hpath/heater_auto oldval 0 + hset $scobj_hpath/heater_auto 0 + + hfactory $scobj_hpath/cooler_auto plain user int + hsetprop $scobj_hpath/cooler_auto values 0,1 + hsetprop $scobj_hpath/cooler_auto oldval 0 + hset $scobj_hpath/cooler_auto 0 + + hfactory $scobj_hpath/apply_tolerance plain user int + hsetprop $scobj_hpath/apply_tolerance values 0,1 + hset $scobj_hpath/apply_tolerance 1 + + hfactory $scobj_hpath/proportional_band plain user float + hsetprop $scobj_hpath/proportional_band read ${ns}::getValue rdValue "R8" + hsetprop $scobj_hpath/proportional_band rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/proportional_band oldval 30.0 + hset $scobj_hpath/proportional_band 30.0 + + hfactory $scobj_hpath/integral_time plain user float + hsetprop $scobj_hpath/integral_time read ${ns}::getValue rdValue "R9" + hsetprop $scobj_hpath/integral_time rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/integral_time oldval 2.0 + hset $scobj_hpath/integral_time 2.0 + + hfactory $scobj_hpath/derivative_time plain user float + hsetprop $scobj_hpath/derivative_time read ${ns}::getValue rdValue "R10" + hsetprop $scobj_hpath/derivative_time rdValue ${ns}::rdValue $scobj_hpath + hsetprop $scobj_hpath/derivative_time oldval 0.0 + hset $scobj_hpath/derivative_time 0.0 + + hfactory $scobj_hpath/tolerance plain user float + hsetprop $scobj_hpath/tolerance units "K" + hfactory $scobj_hpath/tolerance/settletime plain user float + hset $scobj_hpath/tolerance/settletime 5.0 + hsetprop $scobj_hpath/tolerance/settletime units "s" + hset $scobj_hpath/tolerance $tol + + hfactory $scobj_hpath/status plain spy text + hset $scobj_hpath/status "idle" + hsetprop $scobj_hpath/status values busy,idle + + hfactory $scobj_hpath/itc500_state plain spy text + hsetprop $scobj_hpath/itc500_state read ${ns}::getState $scobj_hpath rdState "X" + hsetprop $scobj_hpath/itc500_state rdState ${ns}::rdState $scobj_hpath + hsetprop $scobj_hpath/itc500_state oldval UNKNOWN + hsetprop $scobj_hpath/itc500_state my_state "STATE_V" + hsetprop $scobj_hpath/itc500_state my_status "UNKNOWN" + hsetprop $scobj_hpath/itc500_state my_version UNKNOWN + hsetprop $scobj_hpath/itc500_state my_model UNKNOWN + + hfactory $scobj_hpath/remote_ctrl plain spy text + hset $scobj_hpath/remote_ctrl UNKNOWN + + hfactory $scobj_hpath/itc500_lasterror plain user text + hset $scobj_hpath/itc500_lasterror "" + + hfactory $scobj_hpath/lowerlimit plain mugger float + hsetprop $scobj_hpath/lowerlimit units "K" + hset $scobj_hpath/lowerlimit 0 + + hfactory $scobj_hpath/upperlimit plain mugger float + hsetprop $scobj_hpath/upperlimit units "K" + hset $scobj_hpath/upperlimit 300 + + hfactory $scobj_hpath/emon plain spy none + hfactory $scobj_hpath/emon/monmode plain user text + hsetprop $scobj_hpath/emon/monmode values idle,drive,monitor,error + hset $scobj_hpath/emon/monmode "idle" + hfactory $scobj_hpath/emon/isintol plain user int + hset $scobj_hpath/emon/isintol 1 + hfactory $scobj_hpath/emon/errhandler plain user text + hset $scobj_hpath/emon/errhandler "pause" + + if {[SplitReply [environment_simulation]]=="false"} { + $sct_controller poll $scobj_hpath/setpoint + $sct_controller write $scobj_hpath/setpoint + $sct_controller poll $scobj_hpath/sensor/value + $sct_controller poll $scobj_hpath/sensor2/value + $sct_controller poll $scobj_hpath/sensor3/value + $sct_controller poll $scobj_hpath/heating_power_percent + $sct_controller poll $scobj_hpath/heating_power_volts + $sct_controller poll $scobj_hpath/gas_flow + $sct_controller poll $scobj_hpath/proportional_band + $sct_controller poll $scobj_hpath/integral_time + $sct_controller poll $scobj_hpath/derivative_time + $sct_controller poll $scobj_hpath/itc500_state 5 halt read + } + + ::scobj::hinitprops $tempobj + hsetprop $scobj_hpath klass NXenvironment + ::scobj::set_required_props $scobj_hpath + hsetprop $scobj_hpath type part + foreach snsr {sensor sensor2 sensor3} { + foreach {rootpath hpath klass priv} " + $scobj_hpath $snsr NXsensor spy + $scobj_hpath $snsr/value sensor user + " { + hsetprop $rootpath/$hpath klass $klass + hsetprop $rootpath/$hpath privilege $priv + hsetprop $rootpath/$hpath control true + hsetprop $rootpath/$hpath data true + hsetprop $rootpath/$hpath nxsave true + } + hsetprop $scobj_hpath/$snsr type part + hsetprop $scobj_hpath/$snsr/value nxalias tc1_${snsr}_value + hsetprop $scobj_hpath/$snsr/value mutable true + hsetprop $scobj_hpath/$snsr/value sdsinfo ::nexus::scobj::sdsinfo + } + hsetprop $scobj_hpath privilege spy + ::scobj::hinitprops $tempobj setpoint + if {[SplitReply [environment_simulation]]=="false"} { + ansto_makesctdrive ${tempobj}_driveable $scobj_hpath/setpoint $scobj_hpath/sensor/value $sct_controller + } + } message ] { + return -code error $message + } + } + namespace export mk_sct_oxford_itc500 +} + +## +# @brief Create a Oxford itc500 temperature controller +# +# @param name, the name of the temperature controller (eg tc1) +# @param IP, the IP address of the device, this can be a hostname, (eg ca1-kowari) +# @param port, the IP protocol port number of the device +# @param _tol (optional), this is the initial tolerance setting +proc add_itc500 {name IP port {_tol 5.0}} { + set fd [open "/tmp/itc500.log" a] + if {[SplitReply [environment_simulation]]=="false"} { + puts $fd "makesctcontroller sct_itc500 oxford ${IP}:$port" + makesctcontroller sct_itc500 oxford ${IP}:$port + } + puts $fd "mk_sct_oxford_itc500 sct_itc500 environment $name $_tol" + mk_sct_oxford_itc500 sct_itc500 environment $name $_tol + puts $fd "makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler" + makesctemon $name /sics/$name/emon/monmode /sics/$name/emon/isintol /sics/$name/emon/errhandler + close $fd +} + +puts stdout "file evaluation of sct_oxford_500.tcl" +set fd [open "/tmp/itc500.log" w] +puts $fd "file evaluation of sct_oxford_500.tcl" +close $fd + +namespace import ::scobj::itc500::* + +#add_itc500 itc500 137.157.201.213 502 5 +add_itc500 itc500 localhost 30509 5