From ecf64f40ccd43416233357dc1c91baa459abbb81 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 7 Jun 2013 17:36:01 +1000 Subject: [PATCH 01/10] Add some TODO messages and change the reconnect backoff limits --- asyncqueue.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/asyncqueue.c b/asyncqueue.c index 576900e3..e258feb2 100644 --- a/asyncqueue.c +++ b/asyncqueue.c @@ -144,6 +144,9 @@ static int TimedReconnect(void *cntx, int mode) if (self->state != eAsyncConnected) SICSLogPrintf(eStatus, "Function: %s:%s\n", self->queue_name, __func__); + + /* TODO: if self->pSock is NULL we haven't connected yet */ + iRet = NETReconnect(self->pSock); /* * iRet can take the following values: @@ -158,10 +161,10 @@ static int TimedReconnect(void *cntx, int mode) NetWatchSetMode(self->nw_ctx, 0); /* implement an exponential backoff within limits */ self->retryTimer = 2 * self->retryTimer; - if (self->retryTimer < 250) - self->retryTimer = 250; - if (self->retryTimer > 30000) - self->retryTimer = 30000; + if (self->retryTimer < 125) + self->retryTimer = 125; + if (self->retryTimer > 16000) + self->retryTimer = 16000; NetWatchRegisterTimer(&self->nw_tmr, self->retryTimer, TimedReconnect, self); SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncWaiting\n", @@ -982,6 +985,7 @@ static pAsyncQueue AQ_Create(const char *host, const char *port) } if (self == NULL) { + /* TODO: if channel (self->pSock) is NULL we haven't connected yet, do it later */ if (channel == NULL) return NULL; @@ -1001,6 +1005,15 @@ static pAsyncQueue AQ_Create(const char *host, const char *port) if (i == queue_index) queue_array[queue_index++] = self; + /* TODO: if self->pSock is NULL we haven't connected yet */ +#if 0 + if (channel == NULL) { + /* TODO: all the rest */ + NetWatchRegisterTimer(&self->nw_tmr, self->retryTimer, TimedReconnect, + self); + } +#endif + return self; } From d6f72482b370deea8f9e68e50614a404834ccf74 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Thu, 6 Jun 2013 15:45:04 +1000 Subject: [PATCH 02/10] change state to connected before notify callback for connect --- asyncqueue.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/asyncqueue.c b/asyncqueue.c index e258feb2..fedc9c84 100644 --- a/asyncqueue.c +++ b/asyncqueue.c @@ -178,13 +178,13 @@ static int TimedReconnect(void *cntx, int mode) self->queue_name, __func__, state_name(self->state)); self->state = eAsyncConnecting; } else { - snprintf(line, 132, "Reconnect on AsyncQueue '%s'", self->queue_name); - SICSLogWrite(line, eStatus); - AQ_Notify(self, AQU_RECONNECT); NetWatchSetMode(self->nw_ctx, nwatch_read); SICSLogPrintf(eStatus, "In %s:%s: state %s => eAsyncConnected\n", self->queue_name, __func__, state_name(self->state)); self->state = eAsyncConnected; + snprintf(line, 132, "Reconnect on AsyncQueue '%s'", self->queue_name); + SICSLogWrite(line, eStatus); + AQ_Notify(self, AQU_RECONNECT); } return 1; } From bff8cc2c160d838a2c3cf40e28c6f82a83c3d211 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 14 Jun 2013 13:31:28 +1000 Subject: [PATCH 03/10] Implement limit switches and the SC and TS commands on fake Galil motors --- .../TEST_SICS/fakeGalil/galilcontroller.py | 2 +- .../TEST_SICS/fakeGalil/galilmotor.py | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/site_ansto/instrument/TEST_SICS/fakeGalil/galilcontroller.py b/site_ansto/instrument/TEST_SICS/fakeGalil/galilcontroller.py index aa4bc2aa..ccc8a8ef 100644 --- a/site_ansto/instrument/TEST_SICS/fakeGalil/galilcontroller.py +++ b/site_ansto/instrument/TEST_SICS/fakeGalil/galilcontroller.py @@ -112,7 +112,7 @@ class GalilController(object): def doCommand(self, cmd, arg): action = cmd[0:2] #print "Command %s(%s) = %s" % (action, cmd[2:], arg) - if action in ["BG", "ST", "TP", "TD", "SH", "MO"]: + if action in ["BG", "ST", "TP", "TD", "SH", "MO", "SC", "TS"]: self.doMotorCommand(cmd, arg) if action == "LV": self.doCommandLV(cmd, arg) diff --git a/site_ansto/instrument/TEST_SICS/fakeGalil/galilmotor.py b/site_ansto/instrument/TEST_SICS/fakeGalil/galilmotor.py index ec1dfd4e..5d33429e 100644 --- a/site_ansto/instrument/TEST_SICS/fakeGalil/galilmotor.py +++ b/site_ansto/instrument/TEST_SICS/fakeGalil/galilmotor.py @@ -1,5 +1,5 @@ #!/usr//bin/env python -# vim: ts=8 sts=4 sw=4 expandtab +# vim: ts=8 sts=4 sw=4 ft=python expandtab # Author: Douglas Clowes (dcl@ansto.gov.au) 2012-06-29 import inspect import time @@ -169,8 +169,18 @@ class GalilMotor(object): currentPosition = self.getPosition() if not self.moveCallback == None: self.moveCallback(self) - # TODO Forward Limit - # TODO Reverse Limit + if self.targetSteps > self.motorStartSteps and currentPosition >= self.upperLim: + # Forward Limit + self.motorState = "STOPPED" + self.stopcode = 2 # stopped by forward limit + self.switches = 44 - 8 # stopped, reverse limit clear + pass + if self.targetSteps < self.motorStartSteps and currentPosition <= self.lowerLim: + # Reverse Limit + self.motorState = "STOPPED" + self.stopcode = 3 # stopped by reverse limit + self.switches = 44 - 4 # stopped, forward limit clear + pass if self.motorState == "STOPPED": print "Axis %s stopped at:" % self.axis, currentPosition self.currentSteps = self.targetSteps @@ -243,6 +253,12 @@ class GalilMotor(object): def doCommandTP(self, arg): return self.doQuery("TP") + def doCommandSC(self, arg): + return self.doQuery("SC") + + def doCommandTS(self, arg): + return self.doQuery("TS") + def doCommandST(self, arg): if self.motorState in ["MOVING"]: self.motorState = "STOPPED" From 1ac674099da47a5073dab35e06c80652d39c2f37 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 14 Jun 2013 13:33:08 +1000 Subject: [PATCH 04/10] Fix connection failure logic in AsyncQueue, return if not reconnected --- asyncqueue.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/asyncqueue.c b/asyncqueue.c index fedc9c84..232d96b5 100644 --- a/asyncqueue.c +++ b/asyncqueue.c @@ -300,8 +300,7 @@ static int StartCommand(pAsyncQueue self) iRet = NETRead(sock, reply, 128, 0); if (iRet < 0) { /* EOF */ iRet = AQ_Reconnect(self); - if (iRet == 0) - return 0; + return 0; } else if (iRet > 0) { struct timeval tv; gettimeofday(&tv, NULL); From eb1579de7ddab2ec1ef454fc3ec1d504bbe061b6 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Tue, 18 Jun 2013 17:18:07 +1000 Subject: [PATCH 05/10] The SRCDIR is already included in the INSTSRC variable --- site_ansto/instrument/deploySICS.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site_ansto/instrument/deploySICS.sh b/site_ansto/instrument/deploySICS.sh index 53c4ee01..87d12845 100755 --- a/site_ansto/instrument/deploySICS.sh +++ b/site_ansto/instrument/deploySICS.sh @@ -196,9 +196,9 @@ then echo "$SRCDIR/MANIFEST.TXT not found" exit 1 fi -if [ ! -e $SRCDIR/$INSTSRC/MANIFEST.TXT ] +if [ ! -e $INSTSRC/MANIFEST.TXT ] then -echo "$SRCDIR/$INSTSRC/MANIFEST.TXT not found" +echo "$INSTSRC/MANIFEST.TXT not found" echo "You must list the files required for $INSTRUMENT in the manifest" exit 1 fi From c240e54277b2c4fd219cc2a626ca966837e4f5a4 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Tue, 18 Jun 2013 17:45:01 +1000 Subject: [PATCH 06/10] Create a deployment log in FILEMAP.TXT --- site_ansto/instrument/deploySICS.sh | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/site_ansto/instrument/deploySICS.sh b/site_ansto/instrument/deploySICS.sh index 87d12845..7246960c 100755 --- a/site_ansto/instrument/deploySICS.sh +++ b/site_ansto/instrument/deploySICS.sh @@ -40,14 +40,23 @@ Examples: EOF } +init_file_map() { + echo -n "" >$FILEMAP + echo "TEMPDIR=$TEMPDIR" >>$FILEMAP + echo "SRCDIR=$PWD" >>$FILEMAP + echo "DESTDIR=$DESTDIR" >>$FILEMAP + echo "SICS_SITE=$(bash ../extract_version.sh SITE)" >>$FILEMAP + echo "SICS_VERSION=$(bash ../extract_version.sh VERSION)" >>$FILEMAP + echo "SICS_REVISION=$(bash ../extract_version.sh REVISION)" >>$FILEMAP +} # Copy sics server configuration files to a given destination # Usage: copy_server_config SERVER_DIRECTORY copy_server_config() { sicserver_path=$1 - cp -a --preserve=timestamps $COMMON $INSTSPEC $TEMPDIR/$DESTDIR/$sicserver_path + cp -v -a --preserve=timestamps $COMMON $INSTSPEC $TEMPDIR/$DESTDIR/$sicserver_path >>$FILEMAP if [ -e $INSTCFDIR/INSTCFCOMMON.TXT ]; then for f in $(cat $INSTCFDIR/INSTCFCOMMON.TXT); do - cp --parents --preserve=timestamps $f $TEMPDIR/$DESTDIR/$sicserver_path + cp -v --parents --preserve=timestamps $f $TEMPDIR/$DESTDIR/$sicserver_path >>$FILEMAP done fi } @@ -158,8 +167,10 @@ then # remove and recreate the temporary directory rm -fr $TEMPDIR/$DESTDIR mkdir -p $TEMPDIR/$DESTDIR + FILEMAP=$TEMPDIR/$DESTDIR/FILEMAP.TXT + init_file_map #copy TEST_SICS/fakeDMC and remove .svn any directories - cp -a $SRCDIR/TEST_SICS/* $TEMPDIR/$DESTDIR + cp -v -a $SRCDIR/TEST_SICS/* $TEMPDIR/$DESTDIR >>$FILEMAP rm -fr $(find $TEMPDIR/$DESTDIR -name .svn) # step down to the sics directory DESTDIR=$DESTDIR/$SICSDIR @@ -170,6 +181,8 @@ else # remove and recreate the temporary directory rm -fr $TEMPDIR/$DESTDIR mkdir -p $TEMPDIR/$DESTDIR + FILEMAP=$TEMPDIR/$DESTDIR/FILEMAP.TXT + init_file_map fi # Notify progress and intention @@ -210,7 +223,7 @@ INSTSPEC=$(for f in $(cat $INSTSRC/MANIFEST.TXT); do echo -n "$INSTSRC/$f "; don # Create Instrument Control Server directories and copy SICS configs to the 'server' directory mkdir -p $TEMPDIR/$DESTDIR/{batch,newserver,log,tmp} copy_server_config newserver -cp -a --preserve=timestamps ../SICServer $TEMPDIR/$DESTDIR/newserver +cp -v -a --preserve=timestamps ../SICServer $TEMPDIR/$DESTDIR/newserver >>$FILEMAP # Create Script Validator directories mkdir -p $TEMPDIR/$DESTDIR/script_validator/{data,log,tmp} From 5970a05aaadadba40e8b92bd3403771ced8d11f5 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Wed, 19 Jun 2013 12:35:46 +1000 Subject: [PATCH 07/10] Make the ls370 sct controller name consistent with ls336 and ls340 --- .../config/environment/temperature/sct_lakeshore_370.tcl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/site_ansto/instrument/config/environment/temperature/sct_lakeshore_370.tcl b/site_ansto/instrument/config/environment/temperature/sct_lakeshore_370.tcl index 3bc6f16f..b654085b 100644 --- a/site_ansto/instrument/config/environment/temperature/sct_lakeshore_370.tcl +++ b/site_ansto/instrument/config/environment/temperature/sct_lakeshore_370.tcl @@ -903,11 +903,11 @@ namespace eval ::scobj::[set vendor]_[set device] { set [ns]::log_file "/tmp/[set [ns]::ven_dev]_[set name].log" debug_log 1 "add_[set [ns]::vendor]_[set [ns]::device] ${name} ${IP} ${port} ${_tol}" if {[SplitReply [environment_simulation]]=="false"} { - debug_log 1 "makesctcontroller sct_${name} std ${IP}:${port}" - makesctcontroller sct_${name} std ${IP}:${port} "\r\n" + debug_log 1 "makesctcontroller sct_ls370_${name} std ${IP}:${port}" + makesctcontroller sct_ls370_${name} std ${IP}:${port} "\r\n" } - debug_log 1 "mk_sct_driver sct_${name} environment ${name} ${_tol}" - mk_sct_driver sct_${name} environment ${name} ${_tol} + debug_log 1 "mk_sct_driver sct_ls370_${name} environment ${name} ${_tol}" + mk_sct_driver sct_ls370_${name} environment ${name} ${_tol} } From 95d8a565e308742f50f40ec954e507b4ea2cf8d6 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 21 Jun 2013 13:37:31 +1000 Subject: [PATCH 08/10] Andrew Kerrigan's script context driver for the Pfeiffer 261 pressure gauge --- .../pressure/sct_pfeiffer_tpg261.tcl | 135 ++++++++++++++++++ 1 file changed, 135 insertions(+) create mode 100644 site_ansto/instrument/config/environment/pressure/sct_pfeiffer_tpg261.tcl diff --git a/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_tpg261.tcl b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_tpg261.tcl new file mode 100644 index 00000000..13a5eb4b --- /dev/null +++ b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_tpg261.tcl @@ -0,0 +1,135 @@ +# sct_pfeiffer_tpg261.tcl +# Created 23/1/13 by Andrew Kerrigan, summer student in the ANSTO sample environment +# SICS ScriptContext setup for the pfeiffer 261 pressure gauge +# +# Usage: +# add_tpg261 name IP port [filename] +# +# Example: +# add_tpg261 myObj 137.157.202.78 4004 /home/nbi/pressurelog_060213.txt +# +# This will set up: +# SCT_OBJECT myObj +# SCT_CONTROLLER sct_tpg261_myObj +# Log file /home/nbi/pressurelog_060213.txt +# The SCT_OBJECT has a node "currentPressure" containing the +# current pressure reading from the tpg261 as a float, in whatever +# units the tpg261 is currently reading in +# +# The current pressure will be written to the log file along with a time stamp every time it is polled. + +namespace eval ::scobj::tpg261 { + + proc sendPR1 {par nextState} { + if [hpropexists [sct] geterror] { + hdelprop [sct] geterror + } + sct send "$par" + return $nextState + } + + proc isReady {nextState} { + set data [sct result] + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + set nextState idle + } + default { + if {$data == "\x06"} { + sct send "\x05" + } + } + } + return $nextState + } + + proc getPR1 {path nextState} { + set data [sct result] + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + set nextState idle + } + default { + set val [string range $data 3 12] + set status [string range $data 0 0] + sct update $val + hsetprop ${path}/currentPressure status $status + sct utime readtime + set nextState statusUpdate + if {[hgetpropval $path/currentPressure logging] = 1} { + set floc [hval ${path}/filename] + set fn [open $floc a+] + set curtime [hgetpropval ${path}/currentPressure readtime] + puts $fn "$curtime, $pressure, $status" + close $fn + } + } + return $nextState + } + } + + proc statusUpdate {path} { + set status [hgetpropval $path/currentPressure status] + switch $status { + 0 { set text "Sensor OK" } + 1 { set text "Sensor underrange" } + 2 { set text "Sensor overrange" } + 3 { set text "Sensor error" } + 4 { set text "Sensor off" } + 5 { set text "No sensor" } + 6 { set text "Identification error" } + default { set text "Status unreadable" } + } + hsetprop $path/currentPressure statusText $text + return idle + } + + proc mk_sct_pfeiffer_tpg261 {sct_controller klass tempobj filename} { + set ns ::scobj::tpg261 + makesicsobj $tempobj SCT_OBJECT + sicslist setatt $tempobj klass $klass + sicslist setatt $tempobj long_name $tempobj + + set scobj_hpath /sics/$tempobj + hfactory ${scobj_hpath}/currentPressure plain user float + hsetprop ${scobj_hpath}/currentPressure read ${ns}::sendPR1 "PR1" isReady + hsetprop ${scobj_hpath}/currentPressure isReady ${ns}::isReady getPR1 + hsetprop ${scobj_hpath}/currentPressure getPR1 ${ns}::getPR1 $scobj_hpath statusUpdate + hsetprop ${scobj_hpath}/currentPressure statusUpdate ${ns}::statusUpdate $scobj_hpath + hsetprop ${scobj_hpath}/currentPressure status 0 + hsetprop ${scobj_hpath}/currentPressure statusText UNKNOWN + hsetprop ${scobj_hpath}/currentPressure readtime UNKNOWN + + hfactory ${scobj_hpath}/filename plain user text + hset ${scobj_hpath}/filename $filename + if {$filename = "noFile"} { + hsetprop ${scobj_hpath}/currentPressure logging 0 + } else { + hsetprop ${scobj_hpath}/currentPressure logging 1 + set floc $filename + set fn [open $floc a+] + puts $fn "Time (s), Pressure (mbar), Status" + close $fn + } + + ::scobj::hinitprops $tempobj + ::scobj::set_required_props $scobj_hpath + + if {[SplitReply [environment_simulation]]=="false"} { + $sct_controller poll ${scobj_hpath}/currentPressure + } + } + + proc add_tpg261 {name IP port {filename "noFile"} { + if {[SplitReply [environment_simulation]]=="false"} { + makesctcontroller sct_tpg261_$name std ${IP}:$port "\r\n" + } + mk_sct_pfeiffer_tpg261 sct_tpg261_$name environment $name $filename + } +} +publish ::scobj::tpg261::add_tpg261 user +#::scobj::tpg261::add_tpg261 prgauge 137.157.202.78 4002 +namespace import ::scobj::tpg261::* + From 3dce7feb8e12e4b2c33f6bb3a9885044b95c7eb6 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 21 Jun 2013 13:39:13 +1000 Subject: [PATCH 09/10] Andrew Kerrigan's sct driver for the Pfeiffer pressure gauge and Oxford Mercury --- .../pressure/sct_pfeiffer_mercury.tcl | 243 ++++++++++++++++++ 1 file changed, 243 insertions(+) create mode 100644 site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl diff --git a/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl new file mode 100644 index 00000000..62cdcd10 --- /dev/null +++ b/site_ansto/instrument/config/environment/pressure/sct_pfeiffer_mercury.tcl @@ -0,0 +1,243 @@ +# Andrew Kerrigan +# andrewk@ansto.gov.au / u4673036@anu.edu.au +# +# Driver to control the pressure inside the 12T magnet using a pfeiffer pressure gauge as a pressure readout and the needle valve on the magnet as a pressure/flow control +# +# PID parameters: +# setPoint/control Kp Proportionate control constant +# setPoint/control Ki Integral control constant +# setPoint/control Kd Derivative control constant +# setPoint/control period Period of control loop in seconds +# +# Kp is in units of %/mbar, Ki and Kd follow from that. +# +# Usage: +# add_mercury name IP_mercury Port_mercury IP_pfeiffer Port_pfeiffer filename +# IP_mercury IP address of the mercury iTC on the moxabox +# Port_mercury Port of the mercury iTC on the moxabox +# IP_pfeiffer IP address of the pfeiffer on the moxabox +# Port_pfeiffer Port of the pfeiffer on the moxabox +# filename Name and location of the log file +# +# Example: +# add_mercury mercury 137.157.202.78 4004 137.157.202.78 4002 /home/nbi/AndrewKSICS/MercuryPLoop.txt +# +# The commands to read and set the needle pressure are specific to the setup on the mercury + +namespace eval ::scobj::mercurycontrol { + proc getValue {id type signal nextState path} { + if [hpropexists [sct] geterror] { + hdelprop [sct] geterror + } + sct send "READ:DEV:DB4.G1:AUX:SIG:OPEN" + return $nextState + } + + proc readValue {path} { + set data [sct result] + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + set nextState idle + } + default { + set val [string range $data 29 34] + set oldval [hgetpropval ${path}/sensor/value oldval] + set nextstate idle + if {$val != $oldval} { + sct update $val + sct utime readtime + } + hsetprop ${path}/sensor/value oldval $val + if {[string equal "true" [hgetpropval ${path}/setPoint isSet]]} { + set nextstate controlValve + } + if {[hgetpropval $path/currentPressure logging] = 1} { + set floc [hval ${path}/filename] + set fn [open $floc a+] + set valvepos [hval ${path}/sensor/value] + set pressure [hval ${path}/currentPressure] + set setpoint [hval ${path}/setPoint] + set statustext [hgetpropval ${path}/currentPressure statusText] + set curtime [hgetpropval ${path}/sensor/value readtime] + puts $fn "$curtime, $pressure, $setpoint, $valvepos, $statusText" + close $fn + } + } + return $nextstate + } + + proc controlValve {path} { + set currentTime [clock seconds] + set prevTime [hgetpropval $path/setPoint updateTime] + set elapsed [expr $currentTime - $prevTime] + set period [expr [hgetpropval $path/setPoint/control period]] + + set controlling 1 + #30 second update frequency - the needle valve is fairly slow + if {$elapsed < $period} { + return idle + } else { + hsetprop $path/setPoint updateTime [clock seconds] + } + + set Kp [hgetpropval $path/setPoint/control Kp] + set Ki [hgetpropval $path/setPoint/control Ki] + set Kd [hgetpropval $path/setPoint/control Kd] + set currentError [hgetpropval $path/setPoint/control currentError] + hsetprop $path/setPoint/control prevError $currentError + set currentPressure [expr [hval $path/currentPressure]] + set currentError [expr [hval $path/setPoint] - $currentPressure] + set currentPos [expr [hval $path/sensor/value]] + hsetprop $path/setPoint/control currentError $currentError + set oldIntControl [hgetpropval $path/setPoint/control integralControl] + set integralControl [expr $oldIntControl + $Ki * $currentError] + hsetprop $path/setPoint/control integralControl $integralControl + + set proportionateControl [expr $Kp * $currentError] + set differentialControl [expr $Kd * $currentError - $Kd * $prevError] + set newPos [expr $currentPos + $proportionateControl + $integralControl + $differentialControl] + + if {$controlling} { # Control range is [0.0 - 100.0], the valve won't move if it is set outside this range + if {$newPos > 100} { + set outPos 100.0 + } elseif {$newPos < 0} { + set outPos 0.0 + } else { + set outPos $newPos + } + sct_mercury send "SET:DEV:MB1.T1:TEMP:LOOP:FSET:${outPos}" + } + return idle + } + + proc sendPR1 {par nextState} { + if [hpropexists [sct] geterror] { + hdelprop [sct] geterror + } + sct send "$par" + return $nextState + } + + proc isReady {nextState} { + set data [sct result] + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + set nextState idle + } + default { + if {$data == "\x06"} { + sct send "\x05" + } + } + } + return $nextState + } + + proc getPR1 {path nextState} { + set data [sct result] + switch -glob -- $data { + "ASCERR:*" { + sct geterror $data + set nextState idle + } + default { + set val [string range $data 3 12] + set status [string range $data 0 0] + sct update $val + hsetprop ${path}/currentPressure status $status + sct utime readtime + set nextState statusUpdate + } + return $nextState + } + } + + proc statusUpdate {path} { + set status [hgetpropval $path/currentPressure status] + switch $status { + 0 { set text "Sensor OK" } + 1 { set text "Sensor underrange" } + 2 { set text "Sensor overrange" } + 3 { set text "Sensor error" } + 4 { set text "Sensor off" } + 5 { set text "No sensor" } + 6 { set text "Identification error" } + default { set text "Status unreadable" } + } + hsetprop $path/currentPressure statusText $text + return idle + } + + proc mk_mercury_itc {name sct_mercury sct_pfeiffer klass filename} { + + makesicsobj $name SCT_OBJECT + sicslist setatt $name klass $klass + sicslist setatt $name long_name $name + + set scobj_hpath /sics/$name + set ns ::scobj::mercurycontrol + + hfactory ${scobj_hpath}/sensor plain user none + + hfactory ${scobj_hpath}/sensor/value plain user float + hsetprop ${scobj_hpath}/sensor/value read ${ns}::getValue readValue $scobj_hpath + hsetprop ${scobj_hpath}/sensor/value readValue ${ns}::readValue $scobj_hpath + hsetprop ${scobj_hpath}/sensor/value controlValve ${ns}::controlValve $scobj_hpath + hsetprop ${scobj_hpath}/sensor/value oldval -1.0 + + hfactory ${scobj_hpath}/setPoint plain user float + hsetprop ${scobj_hpath}/setPoint isSet "false" + hsetprop ${scobj_hpath}/setPoint updateTime 0 + + hfactory ${scobj_hpath}/setPoint/control plain user none + hsetprop ${scobj_hpath}/setPoint/control Kp 33.0 + hsetprop ${scobj_hpath}/setPoint/control Ki 0.0 + hsetprop ${scobj_hpath}/setPoint/control Kd 0.0 + hsetprop ${scobj_hpath}/setPoint/control currentError UNKNOWN + hsetprop ${scobj_hpath}/setPoint/control prevError UNKNOWN + hsetprop ${scobj_hpath}/setPoint/control integralControl 0.0 + hsetprop ${scobj_hpath}/setPoint/control period 30 + + hfactory ${scobj_hpath}/currentPressure plain user float + hsetprop ${scobj_hpath}/currentPressure read ${ns}::sendPR1 "PR1" isReady + hsetprop ${scobj_hpath}/currentPressure isReady ${ns}::isReady getPR1 + hsetprop ${scobj_hpath}/currentPressure getPR1 ${ns}::getPR1 $scobj_hpath statusUpdate + hsetprop ${scobj_hpath}/currentPressure statusUpdate ${ns}::statusUpdate $scobj_hpath + hsetprop ${scobj_hpath}/currentPressure status 0 + hsetprop ${scobj_hpath}/currentPressure statusText UNKNOWN + hsetprop ${scobj_hpath}/currentPressure readtime UNKNOWN + + hfactory ${scobj_hpath}/filename plain user text + hset ${scobj_hpath}/filename $filename + if {$filename = "noFile"} { + hsetprop ${scobj_hpath}/currentPressure logging 0 + } else { + hsetprop ${scobj_hpath}/currentPressure logging 1 + set floc $filename + set fn [open $floc a+] + puts $fn "Time (s), Pressure (mbar), Setpoint (mbar), Valve Pos (%), Gauge Status" + close $fn + } + + ::scobj::hinitprops $name + ::scobj::set_required_props $scobj_hpath + + if {[SplitReply [environment_simulation]]=="false"} { + $sct_mercury poll ${scobj_hpath}/sensor/value 1 read read + $sct_pfeiffer poll ${scobj_hpath}/currentPressure 1 read read + } + } + namespace export mk_mercury_itc +} +namespace import ::scobj::mercurycontrol::* +proc add_mercury {name IP_mercury port_mercury IP_pfeiffer port_pfeiffer {filename "noFile"}} { + if {[SplitReply [environment_simulation]]=="false"} { + makesctcontroller sct_mercury std ${IP_mercury}:$port_mercury + makesctcontroller sct_pfeiffer std ${IP_pfeiffer}:$port_pfeiffer + } + mk_mercury_itc $name sct_mercury sct_pfeiffer environment $filename +} + +# add_mercury mercury 137.157.202.78 4004 137.157.202.78 4002 /home/nbi/AndrewKSICS/MercuryPLoop.txt From 2b1e34202d7a8c0d6f891e09bd2791fcbdd38d32 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Fri, 21 Jun 2013 14:27:37 +1000 Subject: [PATCH 10/10] implement fake lakeshore 336, 340 and 370 in Python with curses display --- .../fakeTempControl/lakeshore/LS336.py | 124 ++++ .../fakeTempControl/lakeshore/LS340.py | 124 ++++ .../fakeTempControl/lakeshore/LS370.py | 124 ++++ .../fakeTempControl/lakeshore/Lakeshore336.py | 527 +++++++++++++++++ .../fakeTempControl/lakeshore/Lakeshore340.py | 541 ++++++++++++++++++ .../fakeTempControl/lakeshore/Lakeshore370.py | 472 +++++++++++++++ .../lakeshore/LakeshoreDevice.py | 92 +++ .../lakeshore/LakeshoreFactory.py | 43 ++ .../lakeshore/LakeshoreProtocol.py | 88 +++ .../lakeshore/displayscreen.py | 150 +++++ 10 files changed, 2285 insertions(+) create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS336.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS340.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS370.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore336.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore340.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore370.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreDevice.py create mode 100644 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreFactory.py create mode 100755 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreProtocol.py create mode 100644 site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/displayscreen.py diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS336.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS336.py new file mode 100755 index 00000000..86023cb4 --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS336.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# vim: ts=8 sts=4 sw=4 expandtab +# Author: Douglas Clowes (dcl@ansto.gov.au) 2013-06-03 + +from twisted.internet.task import LoopingCall +from twisted.internet import reactor +from twisted.python import log, usage + +from Lakeshore336 import Lakeshore336 as MYBASE +from LakeshoreFactory import LakeshoreFactory +from LakeshoreProtocol import LakeshoreProtocol +import sys + +from displayscreen import Screen + +class MyOptions(usage.Options): + optFlags = [ + ["window", "w", "Create a display window"], + ] + optParameters = [ + ["logfile", "l", None, "output logfile name"], + ["port", "p", None, "port number to listen on"], + ] + def __init__(self): + usage.Options.__init__(self) + self['files'] = [] + + def parseArgs(self, *args): + for arg in args: + self['files'].append(arg) + +class MyScreen(Screen): + def __init__(self, stdscr): + Screen.__init__(self, stdscr) + + def sendLine(self, txt): + global myDev + myDev.protocol = self + myDev.dataReceived(txt) + + def write(self, txt): + try: + newLine = self.lines[-1] + " => " + txt + del self.lines[-1] + self.addLine(newLine) + except: + pass + +class MYDEV(MYBASE): + def __init__(self): + MYBASE.__init__(self) + print MYDEV.__name__, "ctor" + +def device_display(): + global stdscr, myDev, myOpts, myPort + try: + myDev.doIteration(); + except: + raise + + if not myOpts["window"]: + return + + try: + stdscr.addstr(0, 25, "Identity : %s (%d)" % (myDev.IDN, myPort)) + stdscr.addstr(1, 25, "Temperature: %8.3f" % myDev.KRDG[1]) + stdscr.addstr(2, 25, "Setpoint : %8.3f" % myDev.SETP[1]) + stdscr.addstr(3, 25, "Difference : %8.3f" % (myDev.KRDG[1] - myDev.SETP[1])) + stdscr.addstr(5, 25, "Target : %8.3f" % myDev.TARGET[1]) + stdscr.addstr(6, 25, "Ramp Rate : %8.3f" % myDev.RAMP_RATE[1]) + stdscr.addstr(7, 25, "Ramp On : %8s" % ["No", "Yes"][myDev.RAMP_ON[1]]) + stdscr.addstr(8, 25, "Ramping : %8s" % ["No", "Yes"][myDev.RAMP_ST[1]]) + stdscr.addstr(0, 0, "Random : %8.3f" % myDev.RANDOM) + stdscr.refresh() + except: + raise + +if __name__ == "__main__": + global stdscr, myDev, myOpts, myPort + + myOpts = MyOptions() + try: + myOpts.parseOptions() + except usage.UsageError, errortext: + print '%s: %s' % (sys.argv[0], errortext) + print '%s: Try --help for usage details.' % (sys.argv[0]) + raise SystemExit, 1 + + myDev = MYDEV() + digits = myDev.IDN[10:13] + default_port = 7000 + int(digits) + myPort = default_port + logfile = None + + if myOpts["port"]: + myPort = int(myOpts["port"]) + if myPort < 1025 or myPort > 65535: + myPort = default_port + + if myOpts["window"]: + logfile = "/tmp/Fake_LS%s_%d.log" % (digits, myPort) + + if myOpts["logfile"]: + logfile = myOpts["logfile"] + + if logfile: + log.startLogging(open(logfile, "w")) + else: + log.startLogging(sys.stdout) + #log.startLogging(sys.stderr) + + if myOpts["window"]: + import curses + + stdscr = curses.initscr() + screen = MyScreen(stdscr) + # add screen object as a reader to the reactor + reactor.addReader(screen) + + myFactory = LakeshoreFactory(LakeshoreProtocol, myDev, "\r") + lc = LoopingCall(device_display) + lc.start(0.250) + reactor.listenTCP(myPort, myFactory) # server + reactor.run() diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS340.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS340.py new file mode 100755 index 00000000..9c052f52 --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS340.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# vim: ts=8 sts=4 sw=4 expandtab +# Author: Douglas Clowes (dcl@ansto.gov.au) 2013-06-03 + +from twisted.internet.task import LoopingCall +from twisted.internet import reactor +from twisted.python import log, usage + +from Lakeshore340 import Lakeshore340 as MYBASE +from LakeshoreFactory import LakeshoreFactory +from LakeshoreProtocol import LakeshoreProtocol +import sys + +from displayscreen import Screen + +class MyOptions(usage.Options): + optFlags = [ + ["window", "w", "Create a display window"], + ] + optParameters = [ + ["logfile", "l", None, "output logfile name"], + ["port", "p", None, "port number to listen on"], + ] + def __init__(self): + usage.Options.__init__(self) + self['files'] = [] + + def parseArgs(self, *args): + for arg in args: + self['files'].append(arg) + +class MyScreen(Screen): + def __init__(self, stdscr): + Screen.__init__(self, stdscr) + + def sendLine(self, txt): + global myDev + myDev.protocol = self + myDev.dataReceived(txt) + + def write(self, txt): + try: + newLine = self.lines[-1] + " => " + txt + del self.lines[-1] + self.addLine(newLine) + except: + pass + +class MYDEV(MYBASE): + def __init__(self): + MYBASE.__init__(self) + print MYDEV.__name__, "ctor" + +def device_display(): + global stdscr, myDev, myOpts, myPort + try: + myDev.doIteration(); + except: + raise + + if not myOpts["window"]: + return + + try: + stdscr.addstr(0, 25, "Identity : %s (%d)" % (myDev.IDN, myPort)) + stdscr.addstr(1, 25, "Temperature: %8.3f" % myDev.KRDG[1]) + stdscr.addstr(2, 25, "Setpoint : %8.3f" % myDev.SETP[1]) + stdscr.addstr(3, 25, "Difference : %8.3f" % (myDev.KRDG[1] - myDev.SETP[1])) + stdscr.addstr(5, 25, "Target : %8.3f" % myDev.TARGET[1]) + stdscr.addstr(6, 25, "Ramp Rate : %8.3f" % myDev.RAMP_RATE[1]) + stdscr.addstr(7, 25, "Ramp On : %8s" % ["No", "Yes"][myDev.RAMP_ON[1]]) + stdscr.addstr(8, 25, "Ramping : %8s" % ["No", "Yes"][myDev.RAMP_ST[1]]) + stdscr.addstr(0, 0, "Random : %8.3f" % myDev.RANDOM) + stdscr.refresh() + except: + raise + +if __name__ == "__main__": + global stdscr, myDev, myOpts, myPort + + myOpts = MyOptions() + try: + myOpts.parseOptions() + except usage.UsageError, errortext: + print '%s: %s' % (sys.argv[0], errortext) + print '%s: Try --help for usage details.' % (sys.argv[0]) + raise SystemExit, 1 + + myDev = MYDEV() + digits = myDev.IDN[10:13] + default_port = 7000 + int(digits) + myPort = default_port + logfile = None + + if myOpts["port"]: + myPort = int(myOpts["port"]) + if myPort < 1025 or myPort > 65535: + myPort = default_port + + if myOpts["window"]: + logfile = "/tmp/Fake_LS%s_%d.log" % (digits, myPort) + + if myOpts["logfile"]: + logfile = myOpts["logfile"] + + if logfile: + log.startLogging(open(logfile, "w")) + else: + log.startLogging(sys.stdout) + #log.startLogging(sys.stderr) + + if myOpts["window"]: + import curses + + stdscr = curses.initscr() + screen = MyScreen(stdscr) + # add screen object as a reader to the reactor + reactor.addReader(screen) + + myFactory = LakeshoreFactory(LakeshoreProtocol, myDev, "\r") + lc = LoopingCall(device_display) + lc.start(0.250) + reactor.listenTCP(myPort, myFactory) # server + reactor.run() diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS370.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS370.py new file mode 100755 index 00000000..f74cc779 --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LS370.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# vim: ts=8 sts=4 sw=4 expandtab +# Author: Douglas Clowes (dcl@ansto.gov.au) 2013-06-03 + +from twisted.internet.task import LoopingCall +from twisted.internet import reactor +from twisted.python import log, usage + +from Lakeshore370 import Lakeshore370 as MYBASE +from LakeshoreFactory import LakeshoreFactory +from LakeshoreProtocol import LakeshoreProtocol +import sys + +from displayscreen import Screen + +class MyOptions(usage.Options): + optFlags = [ + ["window", "w", "Create a display window"], + ] + optParameters = [ + ["logfile", "l", None, "output logfile name"], + ["port", "p", None, "port number to listen on"], + ] + def __init__(self): + usage.Options.__init__(self) + self['files'] = [] + + def parseArgs(self, *args): + for arg in args: + self['files'].append(arg) + +class MyScreen(Screen): + def __init__(self, stdscr): + Screen.__init__(self, stdscr) + + def sendLine(self, txt): + global myDev + myDev.protocol = self + myDev.dataReceived(txt) + + def write(self, txt): + try: + newLine = self.lines[-1] + " => " + txt + del self.lines[-1] + self.addLine(newLine) + except: + pass + +class MYDEV(MYBASE): + def __init__(self): + MYBASE.__init__(self) + print MYDEV.__name__, "ctor" + +def device_display(): + global stdscr, myDev, myOpts, myPort + try: + myDev.doIteration(); + except: + raise + + if not myOpts["window"]: + return + + try: + stdscr.addstr(0, 25, "Identity : %s (%d)" % (myDev.IDN, myPort)) + stdscr.addstr(1, 25, "Temperature: %8.3f" % myDev.KRDG[1]) + stdscr.addstr(2, 25, "Setpoint : %8.3f" % myDev.SETP[1]) + stdscr.addstr(3, 25, "Difference : %8.3f" % (myDev.KRDG[1] - myDev.SETP[1])) + stdscr.addstr(5, 25, "Target : %8.3f" % myDev.TARGET[1]) + stdscr.addstr(6, 25, "Ramp Rate : %8.3f" % myDev.RAMP_RATE[1]) + stdscr.addstr(7, 25, "Ramp On : %8s" % ["No", "Yes"][myDev.RAMP_ON[1]]) + stdscr.addstr(8, 25, "Ramping : %8s" % ["No", "Yes"][myDev.RAMP_ST[1]]) + stdscr.addstr(0, 0, "Random : %8.3f" % myDev.RANDOM) + stdscr.refresh() + except: + raise + +if __name__ == "__main__": + global stdscr, myDev, myOpts, myPort + + myOpts = MyOptions() + try: + myOpts.parseOptions() + except usage.UsageError, errortext: + print '%s: %s' % (sys.argv[0], errortext) + print '%s: Try --help for usage details.' % (sys.argv[0]) + raise SystemExit, 1 + + myDev = MYDEV() + digits = myDev.IDN[10:13] + default_port = 7000 + int(digits) + myPort = default_port + logfile = None + + if myOpts["port"]: + myPort = int(myOpts["port"]) + if myPort < 1025 or myPort > 65535: + myPort = default_port + + if myOpts["window"]: + logfile = "/tmp/Fake_LS%s_%d.log" % (digits, myPort) + + if myOpts["logfile"]: + logfile = myOpts["logfile"] + + if logfile: + log.startLogging(open(logfile, "w")) + else: + log.startLogging(sys.stdout) + #log.startLogging(sys.stderr) + + if myOpts["window"]: + import curses + + stdscr = curses.initscr() + screen = MyScreen(stdscr) + # add screen object as a reader to the reactor + reactor.addReader(screen) + + myFactory = LakeshoreFactory(LakeshoreProtocol, myDev, "\r") + lc = LoopingCall(device_display) + lc.start(0.250) + reactor.listenTCP(myPort, myFactory) # server + reactor.run() diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore336.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore336.py new file mode 100755 index 00000000..7ebdba3d --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore336.py @@ -0,0 +1,527 @@ +# vim: ts=8 sts=4 sw=4 expandtab +# Fake Lakeshore Model 336 Temperature Controller +# +# Author: Douglas Clowes 2012, 2013 +# +from LakeshoreDevice import LakeshoreDevice +import random +import re +import sys +import time + +class Lakeshore336(LakeshoreDevice): + """Lakeshore 336 temperature controller object - simulates the LS336""" + + def __init__(self): + LakeshoreDevice.__init__(self) + print Lakeshore336.__name__, "ctor" + self.CONFIG_LOOPS = [1, 2, 3, 4] + self.CONFIG_SNSRS = [1, 2, 3, 4] + self.reset_powerup() + + def doCommand(self, command, params): + print Lakeshore336.__name__, "Command:", command, params + return LakeshoreDevice.doCommand(self, command, params) + + def doQuery(self, command, params): + print Lakeshore336.__name__, "Query:", command, params + return LakeshoreDevice.doQuery(self, command, params) + + def reset_powerup(self): + print Lakeshore336.__name__, "reset_powerup" + self.LAST_ITERATION = 0 + self.ALARM = {} + self.ALARMST = {} + for idx in self.CONFIG_SNSRS: + self.ALARM[idx] = "0" + self.ALARMST[idx] = "0" + self.ANALOG = {1: "0,1,1,1,400.0,0.0,0.0", 2: "0,1,1,1,400.0,0.0,0.0"} + self.AOUT = { 1: 0.0, 2: 0.0 } + self.CFILT = {1: 1, 2: 1} + self.CLIMI = 0.0 + self.CLIMIT = {1: "400.0,10,0,0", 2: "400.0,10,0,0"} + self.CMODE = {} + for idx in self.CONFIG_LOOPS: + self.CMODE[idx] = 1 + self.CRVHDR = {} + self.CRVHDR[1] = "DT-336-1 ,STANDARD ,1,+500.000,1" + self.CRVHDR[2] = "DT-336-2 ,STANDARD ,2,+0.500,1" + self.CRVHDR[3] = "DT-336-3 ,STANDARD ,3,+2.000,2" + self.CRVHDR[4] = "DT-336-4 ,STANDARD ,4,+0.301,2" + self.CRVPT = {} + for i in range(1,21): + self.CRVPT[i] = [(0.0, 0.0)] + self.CSET = {1: "A,1,1,0", 2: "B,1,1,0"} + self.DOUT = 0 + self.FILTER = {1: "1,10,2"} + self.FREQ = 2 + self.GUARD = 0 + self.HTR = 0.0 + self.HTRRNG = 0 + self.HTRST = 0 + self.IDN = "LSCI,MODEL336,123456/123456,1.0" + self.IEEE = "0,0,4" + self.INCRV = {} + self.INTYPE = {} + for idx in self.CONFIG_SNSRS: + self.INCRV[idx] = "1" + self.INTYPE[idx] = "1,0,1,0,1" + self.KEYST = 1 + self.KRDG = {} + for idx in self.CONFIG_SNSRS: + self.KRDG[idx] = 300.0 + self.LOCK = "0,000" + self.MDAT = {1: "0,0,1"} # Min,Max,Reset + self.MOUT = {1: "0.0", 2: "0.0", 3: "0.0", 4: "0.0"} + self.OUTMODE = {1: "1,1,0", 2: "1,2,0", 3: "1,3,0", 4: "1,4,0"} + self.PID = {1: "+0150.0,+0005.0,+000.0", 2: "+0150.0,+0005.0,+000.0"} + self.RAMP_ON = {1: 0, 2: 0} + self.RAMP_RATE = {1: 0.000, 2: 0.000} + self.RAMP_ST = {1: 0, 2:0} + self.RAMP_TIME = 0.0 + self.RANGE = {} + for idx in range(1,5): + self.RANGE[idx] = "1" + self.RDGST = {"A": 0, "B": 0, "C": 0, "D": 0} + self.RELAY = {1: "1,A,0", 2: "2,A,0"} + self.RELAYST = {1: "0", 2: "0"} + self.SETP = {} + self.TARGET = {} + self.RAMP_START_TEMP = {} + self.RAMP_START_TIME = {} + for idx in self.CONFIG_LOOPS: + self.SETP[idx] = 300.0 + self.TARGET[idx] = 300.0 + self.RAMP_START_TEMP[idx] = 300.0 + self.RAMP_START_TIME[idx] = 0.0 + self.STB = 0 + self.ESE = 0 + self.ESR = 0 + self.OPC = 0 + self.SRE = 0 + self.TST = 0 + self.RANDOM = 0.5 + + def doIteration(self): + delta_time = time.time() - self.LAST_ITERATION + if delta_time < 1: + return + #print "DoIteration:", delta_time + self.LAST_ITERATION = time.time() + for idx in self.CONFIG_LOOPS: + # TODO - progress ramping setpoints (SP) + if idx in self.RAMP_ON and self.RAMP_ON[idx] and self.TARGET[idx] != self.SETP[idx]: + delta_time = time.time() - self.RAMP_START_TIME[idx]; + delta_temp = self.RAMP_RATE[idx] * (delta_time / 60.0) + if self.TARGET[idx] > self.RAMP_START_TEMP[idx]: + self.SETP[idx] = self.RAMP_START_TEMP[idx] + delta_temp + if self.SETP[idx] >= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + else: + self.SETP[idx] = self.RAMP_START_TEMP[idx] - delta_temp + if self.SETP[idx] <= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + + # TODO - iterate Power Level + if self.KRDG[idx] <> self.SETP[idx]: + self.HTR = self.SETP[idx] - self.KRDG[idx] + if self.HTR > 100.0: + self.HTR = 100.0 + elif self.HTR < -100.0: + self.HTR = -100.0 + + # TODO - iterate Process Values (PV) + self.KRDG[idx] = (0.9 * self.KRDG[idx] + 0.1 * self.SETP[idx]) + + def doCommandCLS(self, cmd, args): + print "Unimplemented Command: \"*CLS\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandESE(self, cmd, args): + self.ESE = int(args[0]) & 0xFF + def doQueryESE(self, cmd, args): + self.write("%d" % self.ESE) + def doQueryESR(self, cmd, args): + self.write("%d" % self.ESR) + def doQueryIDN(self, cmd, args): + self.write(self.IDN) + def doCommandOPC(self, cmd, args): + self.OPC = 1 + def doQueryOPC(self, cmd, args): + self.write("1") + def doCommandRST(self, cmd, args): + print "Unimplemented Command: \"*RST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandSRE(self, cmd, args): + self.SRE = int(args[0]) & 0xFF + def doQuerySRE(self, cmd, args): + self.write("%d" % self.SRE) + def doQuerySTB(self, cmd, args): + self.write("%d" % self.STB) + def doQueryTST(self, cmd, args): + self.write("%d" % self.TST) + def doCommandWAI(self, cmd, args): + print "Unimplemented Command: \"*WAI\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandALARM(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + params = args[1:].join(",") + if idx in self.ALARM: + self.ALARM[idx] = params + def doQueryALARM(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + if idx in self.ALARM: + self.write(self.ALARM[idx]) + else: + self.write("0,1,500.0,0.0,0") + def doQueryALARMST(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + if idx in self.ALARMST: + self.write(self.ALARMST[idx]) + else: + self.write("0,0") + def doCommandALMRST(self, cmd, args): + for key in self.ALARMST.keys(): + self.ALARMST[key] = "0,0" + def doCommandANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.ANALOG[key] = ",".join(args[1:]) + print "TODO implement Command: \"ANALOG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write(self.ANALOG[key]) # TODO + print "TODO implement Query: \"ANALOG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryAOUT(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write("%6.3f" % self.AOUT[key]) # TODO + print "TODO implement Query: \"AOUT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandBEEP(self, cmd, args): + print "Unimplemented Command: \"BEEP\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBEEP(self, cmd, args): + print "Unimplemented Query: \"BEEP?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBUSY(self, cmd, args): + self.write("0") + def doCommandCDISP(self, cmd, args): + print "Unimplemented Command: \"CDISP\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCDISP(self, cmd, args): + print "Unimplemented Query: \"CDISP?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCFILT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CFILT[loop] = int(args[1]) + def doQueryCFILT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%d" % self.CFILT[loop]) + def doCommandCLIMI(self, cmd, args): + self.CLIMI = double(args[0]) + def doQueryCLIMI(self, cmd, args): + self.write("%f" % self.CLIMI) + def doCommandCLIMIT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CLIMIT[loop] = ",".join(args[1:]) + def doQueryCLIMIT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%s" % self.CLIMIT[loop]) + def doCommandCMODE(self, cmd, args): + loop = int(args[0]) + if loop in self.CMODE: + self.CMODE[loop] = int(args[1]) + def doQueryCMODE(self, cmd, args): + loop = int(args[0]) + if loop in self.CMODE: + self.write("%f" % self.CMODE[loop]) + def doCommandCOMM(self, cmd, args): + self.COMM = ",".join(args) + def doQueryCOMM(self, cmd, args): + self.write("%f" % self.COMM) + def doQueryCRDG(self, cmd, args): + loop = ord(args[0]) - 64 + if loop < 1: + loop = 1 + if loop > 4: + loop = 4 + self.write("%f" % (self.KRDG[loop] - 273.15 + self.RANDOM)) + def doCommandCRVDEL(self, cmd, args): + print "Unimplemented Command: \"CRVDEL\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVHDR(self, cmd, args): + print "Unimplemented Command: \"CRVHDR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVHDR(self, cmd, args): + key = int(args[0]) + if key in self.CRVHDR: + self.write(self.CRVHDR[key]) + else: + self.write("DT-336-1 ,STANDARD ,1,+500.000,1") # TODO + print "TODO implement Query: \"CRVHDR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + # TODO set the Curve Point + print "TODO implement Command: \"CRVPT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + self.write("1.0E+01,1.0+E02") # TODO + print "TODO implement Query: \"CRVPT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVSAV(self, cmd, args): + pass + def doCommandCSET(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CSET[loop] = ",".join(args[1:]) + def doQueryCSET(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%s" % self.CSET[loop]) + def doCommandDFLT(self, cmd, args): + if args[0] == "99": + print "Unimplemented Command: \"DFLT 99\" in \"" + cmd + " " + ",".join(args) + "\"" + else: + print "Invalid Command: \"DFLT " + args[0] + "\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLAY(self, cmd, args): + print "Unimplemented Command: \"DISPLAY\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLAY(self, cmd, args): + print "Unimplemented Query: \"DISPLAY?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLOC(self, cmd, args): + print "Unimplemented Command: \"DISPLOC\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLOC(self, cmd, args): + print "Unimplemented Query: \"DISPLOC?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDOUT(self, cmd, args): + self.DOUT = int(args[0]) + def doQueryDOUT(self, cmd, args): + self.write("%d" % self.DOUT) + def doCommandFILTER(self, cmd, args): + if len(args) > 0: + if int(args[0]) in self.FILTER: + keys = [int(args)] + else: + keys = self.FILTER.keys() + params = args[1:].join(",") + for key in keys: + self.FILTER[key] = params + def doQueryFILTER(self, cmd, args): + idx = int(args[0]) + if idx in self.FILTER: + self.write(self.FILTER[idx]) + else: + self.write("0") + def doQueryHTR(self, cmd, args): + self.write("%f" % self.HTR) + def doQueryHTRST(self, cmd, args): + self.write("%d" % self.HTRST) + def doQueryIEEE(self, cmd, args): + self.write("%s" % self.IEEE) + def doCommandIEEE(self, cmd, args): + self.IEEE = args[0] + def doQueryINCRV(self, cmd, args): + idx = ord(args[0]) - 64 + if idx in self.INCRV: + self.write(self.INCRV[idx]) + else: + self.write("0") + def doCommandINCRV(self, cmd, args): + if len(args) > 1: + idx = ord(args[0]) - 64 + if idx in self.INCRV: + for key in keys: + self.INCRV[key] = args[1] + def doQueryINTYPE(self, cmd, args): + idx = ord(args[0]) - 64 + if idx in self.INTYPE: + self.write(self.INTYPE[idx]) + else: + self.write("0") + def doCommandINTYPE(self, cmd, args): + if len(args) > 1: + idx = ord(args[0]) - 64 + if idx in self.INTYPE: + for key in keys: + self.INTYPE[key] = ",".join(args[1:]) + def doQueryKEYST(self, cmd, args): + self.write("%d" % self.KEYST) + self.KEYST = 0 + def doQueryKRDG(self, cmd, args): + loop = ord(args[0]) - 64 + if loop < 1: + loop = 1 + if loop > 4: + loop = 4 + self.write("%f" % (self.KRDG[loop] + self.RANDOM)) + def doQueryLDAT(self, cmd, args): + self.write("3.000E+02") # TODO + print "TODO implement Query: \"LDAT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLINEAR(self, cmd, args): + self.write("1,1.0,1,3") # TODO + print "TODO implement Query: \"LINEAR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandLINEAR(self, cmd, args): + print "Unimplemented Command: \"LINEAR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLOCK(self, cmd, args): + self.write("%s" % self.LOCK) + def doCommandLOCK(self, cmd, args): + self.LOCK = args[0] + def doQueryMDAT(self, cmd, args): + response = "0" + if len(args[0]) > 0: + idx = int(args[0]) + if idx in self.MDAT: + (minv, maxv, reset) = self.MDAT[idx].split(",") + response = "%f,%f" % (float(minv), float(maxv)) + self.write(response) + def doQueryMNMX(self, cmd, args): + self.write("1") # TODO + print "TODO implement Query: \"MNMX?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMX(self, cmd, args): + print "Unimplemented Command: \"MNMX\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMXRST(self, cmd, args): + print "Unimplemented Command: \"MNMXRST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMODE(self, cmd, args): + print "Unimplemented Query: \"MODE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMODE(self, cmd, args): + print "Unimplemented Command: \"MODE\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMONITOR(self, cmd, args): + print "Unimplemented Query: \"MONITOR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMONITOR(self, cmd, args): + print "Unimplemented Command: \"MONITOR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMOUT(self, cmd, args): + idx = int(args[0]) + self.write(self.MOUT[idx]) + def doCommandMOUT(self, cmd, args): + print "Unimplemented Command: \"MOUT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryOUTMODE(self, cmd, args): + idx = int(args[0]) + if idx in self.OUTMODE: + self.write(self.OUTMODE[idx]) + else: + self.write(self.OUTMODE[1]) + def doCommandOUTMODE(self, cmd, args): + print "Unimplemented Command: \"OUTMODE\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryPID(self, cmd, args): + idx = int(args[0]) + self.write(self.PID[idx]) + def doCommandPID(self, cmd, args): + print "Unimplemented Command: \"PID\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRANGE(self, cmd, args): + idx = int(args[0]) + self.write(self.RANGE[idx]) + def doCommandRANGE(self, cmd, args): + idx = int(args[0]) + val = int(args[1]) + self.RANGE[idx] = val + def doQueryRAMP(self, cmd, args): + idx = int(args[0]) + response = "%d,%f" % (self.RAMP_ON[idx], self.RAMP_RATE[idx]) + self.write(response) + def doCommandRAMP(self, cmd, args): + idx = int(args[0]) + ramp_on = int(args[1]) + if ramp_on == 0 or ramp_on == 1: + self.RAMP_ON[idx] = ramp_on + if ramp_on == 1: + ramp_rate = float(args[2]) + if ramp_rate >= 0.001 and ramp_rate <= 100.0: + self.RAMP_RATE[idx] = ramp_rate + def doQueryRAMPST(self, cmd, args): + idx = int(args[0]) + response = "%d" % self.RAMP_ST[idx] + self.write(response) + def doQueryRDGPWR(self, cmd, args): + self.write("1.000E-15") # TODO + print "TODO implement Query: \"RDGPWR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGR(self, cmd, args): + self.write("1.000E+03") # TODO + print "TODO implement Query: \"RDGR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGRNG(self, cmd, args): + self.write("1,1,19,0,0") # TODO + print "TODO implement Query: \"RDGRNG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandRDGRNG(self, cmd, args): + print "Unimplemented Command: \"RDGRNG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGST(self, cmd, args): + self.write("000") + print "TODO implement Query: \"RDGST?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRELAY(self, cmd, args): + idx = int(args[0]) + self.write(self.RELAY[idx]) + def doCommandRELAY(self, cmd, args): + idx = int(args[0]) + if idx in self.RELAY: + self.relay[idx] = ",".join(args[1:]) + def doQueryRELAYST(self, cmd, args): + idx = int(args[0]) + self.write(self.RELAYST[idx]) + def doQuerySETP(self, cmd, args): + idx = int(args[0]) + val = self.SETP[idx] + self.write("%f" % val) + def doCommandSETP(self, cmd, args): + idx = int(args[0]) + val = float(args[1]) + if (val >= 0.0 and val <= 500.0): + self.TARGET[idx] = val + if self.RAMP_ON[idx] == 0: + self.SETP[idx] = val + self.RAMP_ST[idx] = 0 + else: + self.RAMP_START_TEMP[idx] = self.SETP[idx] + self.RAMP_START_TIME[idx] = time.time() + self.RAMP_ST[idx] = 1 + def doQueryZONE(self, cmd, args): + print "Unimplemented Query: \"ZONE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandZONE(self, cmd, args): + print "Unimplemented Command: \"ZONE\" in \"" + cmd + " " + ",".join(args) + "\"" + +if __name__ == '__main__': + from LakeshoreProtocol import LakeshoreProtocol + + class TestFactory: + def __init__(self): + print self.__class__.__name__, "ctor" + self.numProtocols = 0 + def write(self, data): + print "test write:", data, + def loseConnection(self): + print "test lose connection" + test_factory = TestFactory() + test_device = Lakeshore336() + test_protocol = LakeshoreProtocol(test_device, "\r\n") + test_protocol.factory = test_factory + test_protocol.transport = test_factory + test_device.protocol = test_protocol + test_device.protocol.connectionMade() + test_device.protocol.dataReceived("*IDN?") + test_device.protocol.dataReceived("*TST?") + test_device.protocol.connectionLost("Dunno") diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore340.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore340.py new file mode 100755 index 00000000..8b97c5bf --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore340.py @@ -0,0 +1,541 @@ +# vim: ts=8 sts=4 sw=4 expandtab +# Fake Lakeshore Model 340 Temperature Controller +# +# Author: Douglas Clowes 2012, 2013 +# +from LakeshoreDevice import LakeshoreDevice +import random +import re +import sys +import time + +class Lakeshore340(LakeshoreDevice): + """Lakeshore 340 temperature controller object - simulates the LS340""" + + def __init__(self): + LakeshoreDevice.__init__(self) + print Lakeshore340.__name__, "ctor" + self.CONFIG_LOOPS = [1, 2] + self.CONFIG_SNSRS = [1, 2, 3, 4] + self.reset_powerup() + + def doCommand(self, command, params): + print Lakeshore340.__name__, "Command:", command, params + return LakeshoreDevice.doCommand(self, command, params) + + def doQuery(self, command, params): + print Lakeshore340.__name__, "Query:", command, params + return LakeshoreDevice.doQuery(self, command, params) + + def reset_powerup(self): + print Lakeshore340.__name__, "reset_powerup" + self.LAST_ITERATION = 0 + self.ALARM = {} + self.ALARMST = {} + for idx in self.CONFIG_SNSRS: + self.ALARM[idx] = "0" + self.ALARMST[idx] = "0" + self.ANALOG = {1: "0,1,1,1,400.0,0.0,0.0", 2: "0,1,1,1,400.0,0.0,0.0"} + self.AOUT = { 1: 0.0, 2: 0.0 } + self.CFILT = {1: 1, 2: 1} + self.CLIMI = 0.0 + self.CLIMIT = {1: "400.0,10,0,0", 2: "400.0,10,0,0"} + self.CMODE = {} + for idx in self.CONFIG_LOOPS: + self.CMODE[idx] = 1 + self.CRVHDR = {} + self.CRVHDR[1] = "DT-336-1 ,STANDARD ,1,+500.000,1" + self.CRVHDR[2] = "DT-336-2 ,STANDARD ,2,+0.500,1" + self.CRVHDR[3] = "DT-336-3 ,STANDARD ,3,+2.000,2" + self.CRVHDR[4] = "DT-336-4 ,STANDARD ,4,+0.301,2" + self.CRVPT = {} + for i in range(1,21): + self.CRVPT[i] = [(0.0, 0.0)] + self.CSET = {1: "A,1,1,0", 2: "B,1,1,0"} + self.DOUT = 0 + self.FILTER = {1: "1,10,2"} + self.FREQ = 2 + self.GUARD = 0 + self.HTR = 0.0 + self.HTRRNG = 0 + self.HTRST = 0 + self.IDN = "LSCI,MODEL340,123456,01022003" + self.IEEE = "0,0,4" + self.INCRV = {} + self.INSET = {} + self.INTYPE = {} + for idx in self.CONFIG_SNSRS: + self.INCRV[idx] = "1" + self.INSET[idx] = "1,0" + self.INTYPE[idx] = "1,0,1,0,1" + self.KEYST = 1 + self.KRDG = {} + for idx in self.CONFIG_SNSRS: + self.KRDG[idx] = 300.0 + self.LOCK = "0,000" + self.MDAT = {1: "0,0,1"} # Min,Max,Reset + self.MOUT = {1: "0.0", 2: "0.0", 3: "0.0", 4: "0.0"} + self.OUTMODE = {1: "1,1,0", 2: "1,2,0", 3: "1,3,0", 4: "1,4,0"} + self.PID = {1: "+0150.0,+0005.0,+000.0", 2: "+0150.0,+0005.0,+000.0"} + self.RAMP_ON = {1: 0, 2: 0} + self.RAMP_RATE = {1: 0.000, 2: 0.000} + self.RAMP_ST = {1: 0, 2:0} + self.RAMP_TIME = 0.0 + self.RANGE = {} + for idx in range(1,5): + self.RANGE[idx] = "1" + self.RDGST = {"A": 0, "B": 0, "C": 0, "D": 0} + self.RELAY = {1: "1,A,0", 2: "2,A,0"} + self.RELAYST = {1: "0", 2: "0"} + self.SETTLE = "10.0,10" + self.SETP = {} + self.TARGET = {} + self.RAMP_START_TEMP = {} + self.RAMP_START_TIME = {} + for idx in self.CONFIG_LOOPS: + self.SETP[idx] = 300.0 + self.TARGET[idx] = 300.0 + self.RAMP_START_TEMP[idx] = 300.0 + self.RAMP_START_TIME[idx] = 0.0 + self.STB = 0 + self.ESE = 0 + self.ESR = 0 + self.OPC = 0 + self.SRE = 0 + self.TST = 0 + self.RANDOM = 0.5 + + def doIteration(self): + delta_time = time.time() - self.LAST_ITERATION + if delta_time < 1: + return + #print "DoIteration:", delta_time + self.LAST_ITERATION = time.time() + for idx in self.CONFIG_LOOPS: + # TODO - progress ramping setpoints (SP) + if idx in self.RAMP_ON and self.RAMP_ON[idx] and self.TARGET[idx] != self.SETP[idx]: + delta_time = time.time() - self.RAMP_START_TIME[idx]; + delta_temp = self.RAMP_RATE[idx] * (delta_time / 60.0) + if self.TARGET[idx] > self.RAMP_START_TEMP[idx]: + self.SETP[idx] = self.RAMP_START_TEMP[idx] + delta_temp + if self.SETP[idx] >= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + else: + self.SETP[idx] = self.RAMP_START_TEMP[idx] - delta_temp + if self.SETP[idx] <= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + + # TODO - iterate Power Level + if self.KRDG[idx] <> self.SETP[idx]: + self.HTR = self.SETP[idx] - self.KRDG[idx] + if self.HTR > 100.0: + self.HTR = 100.0 + elif self.HTR < -100.0: + self.HTR = -100.0 + + # TODO - iterate Process Values (PV) + self.KRDG[idx] = (0.9 * self.KRDG[idx] + 0.1 * self.SETP[idx]) + + def doCommandCLS(self, cmd, args): + print "Unimplemented Command: \"*CLS\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandESE(self, cmd, args): + self.ESE = int(args[0]) & 0xFF + def doQueryESE(self, cmd, args): + self.write("%d" % self.ESE) + def doQueryESR(self, cmd, args): + self.write("%d" % self.ESR) + def doQueryIDN(self, cmd, args): + self.write(self.IDN) + def doCommandOPC(self, cmd, args): + self.OPC = 1 + def doQueryOPC(self, cmd, args): + self.write("1") + def doCommandRST(self, cmd, args): + print "Unimplemented Command: \"*RST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandSRE(self, cmd, args): + self.SRE = int(args[0]) & 0xFF + def doQuerySRE(self, cmd, args): + self.write("%d" % self.SRE) + def doQuerySTB(self, cmd, args): + self.write("%d" % self.STB) + def doQueryTST(self, cmd, args): + self.write("%d" % self.TST) + def doCommandWAI(self, cmd, args): + print "Unimplemented Command: \"*WAI\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandALARM(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + params = args[1:].join(",") + if idx in self.ALARM: + self.ALARM[idx] = params + def doQueryALARM(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + if idx in self.ALARM: + self.write(self.ALARM[idx]) + else: + self.write("0,1,500.0,0.0,0") + def doQueryALARMST(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) - 64 + if idx in self.ALARMST: + self.write(self.ALARMST[idx]) + else: + self.write("0,0") + def doCommandALMRST(self, cmd, args): + for key in self.ALARMST.keys(): + self.ALARMST[key] = "0,0" + def doCommandANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.ANALOG[key] = ",".join(args[1:]) + print "TODO implement Command: \"ANALOG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write(self.ANALOG[key]) # TODO + print "TODO implement Query: \"ANALOG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryAOUT(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write("%6.3f" % self.AOUT[key]) # TODO + print "TODO implement Query: \"AOUT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandBEEP(self, cmd, args): + print "Unimplemented Command: \"BEEP\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBEEP(self, cmd, args): + print "Unimplemented Query: \"BEEP?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBUSY(self, cmd, args): + self.write("0") + def doCommandCDISP(self, cmd, args): + print "Unimplemented Command: \"CDISP\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCDISP(self, cmd, args): + print "Unimplemented Query: \"CDISP?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCFILT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CFILT[loop] = int(args[1]) + def doQueryCFILT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%d" % self.CFILT[loop]) + def doCommandCLIMI(self, cmd, args): + self.CLIMI = double(args[0]) + def doQueryCLIMI(self, cmd, args): + self.write("%f" % self.CLIMI) + def doCommandCLIMIT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CLIMIT[loop] = ",".join(args[1:]) + def doQueryCLIMIT(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%s" % self.CLIMIT[loop]) + def doCommandCMODE(self, cmd, args): + loop = int(args[0]) + if loop in self.CMODE: + self.CMODE[loop] = int(args[1]) + def doQueryCMODE(self, cmd, args): + loop = int(args[0]) + if loop in self.CMODE: + self.write("%f" % self.CMODE[loop]) + def doCommandCOMM(self, cmd, args): + self.COMM = ",".join(args) + def doQueryCOMM(self, cmd, args): + self.write("%f" % self.COMM) + def doQueryCRDG(self, cmd, args): + loop = ord(args[0]) - 64 + if loop < 1: + loop = 1 + if loop > 4: + loop = 4 + self.write("%f" % (self.KRDG[loop] - 273.15 + self.RANDOM)) + def doCommandCRVDEL(self, cmd, args): + print "Unimplemented Command: \"CRVDEL\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVHDR(self, cmd, args): + print "Unimplemented Command: \"CRVHDR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVHDR(self, cmd, args): + key = int(args[0]) + if key in self.CRVHDR: + self.write(self.CRVHDR[key]) + else: + self.write("DT-336-1 ,STANDARD ,1,+500.000,1") # TODO + print "TODO implement Query: \"CRVHDR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + # TODO set the Curve Point + print "TODO implement Command: \"CRVPT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + self.write("1.0E+01,1.0+E02") # TODO + print "TODO implement Query: \"CRVPT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVSAV(self, cmd, args): + pass + def doCommandCSET(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.CSET[loop] = ",".join(args[1:]) + def doQueryCSET(self, cmd, args): + loop = int(args[0]) + if loop < 1: + loop = 1 + if loop > 2: + loop = 2 + self.write("%s" % self.CSET[loop]) + def doCommandDATETIME(self, cmd, args): + print "Unimplemented Command: \"DATETIME\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDATETIME(self, cmd, args): + self.write("2,3,1996,15,30,0,0") # TODO + def doCommandDFLT(self, cmd, args): + if args[0] == "99": + print "Unimplemented Command: \"DFLT 99\" in \"" + cmd + " " + ",".join(args) + "\"" + else: + print "Invalid Command: \"DFLT " + args[0] + "\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLAY(self, cmd, args): + print "Unimplemented Command: \"DISPLAY\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLAY(self, cmd, args): + print "Unimplemented Query: \"DISPLAY?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLOC(self, cmd, args): + print "Unimplemented Command: \"DISPLOC\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLOC(self, cmd, args): + print "Unimplemented Query: \"DISPLOC?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDOUT(self, cmd, args): + self.DOUT = int(args[0]) + def doQueryDOUT(self, cmd, args): + self.write("%d" % self.DOUT) + def doCommandFILTER(self, cmd, args): + if len(args) > 0: + if int(args[0]) in self.FILTER: + keys = [int(args)] + else: + keys = self.FILTER.keys() + params = args[1:].join(",") + for key in keys: + self.FILTER[key] = params + def doQueryFILTER(self, cmd, args): + idx = int(args[0]) + if idx in self.FILTER: + self.write(self.FILTER[idx]) + else: + self.write("0") + def doQueryHTR(self, cmd, args): + self.write("%f" % self.HTR) + def doQueryHTRST(self, cmd, args): + self.write("%d" % self.HTRST) + def doQueryIEEE(self, cmd, args): + self.write("%s" % self.IEEE) + def doCommandIEEE(self, cmd, args): + self.IEEE = args[0] + def doQueryINCRV(self, cmd, args): + idx = ord(args[0]) - 64 + if idx in self.INCRV: + self.write(self.INCRV[idx]) + else: + self.write("0") + def doCommandINCRV(self, cmd, args): + if len(args) > 1: + idx = ord(args[0]) - 64 + if idx in self.INCRV: + for key in keys: + self.INCRV[key] = args[1] + def doQueryINTYPE(self, cmd, args): + idx = ord(args[0]) - 64 + if idx in self.INTYPE: + self.write(self.INTYPE[idx]) + else: + self.write("0") + def doQueryINSET(self, cmd, args): + idx = ord(args[0]) + if idx in self.INSET: + self.write(self.INSET[idx]) + else: + self.write("0,0") + def doCommandINSET(self, cmd, args): + if len(args) > 0: + idx = ord(args[0]) + if idx in self.INSET: + self.INSET[idx] = ",".join(args[1:]) + def doCommandINTYPE(self, cmd, args): + if len(args) > 1: + idx = ord(args[0]) - 64 + if idx in self.INTYPE: + for key in keys: + self.INTYPE[key] = ",".join(args[1:]) + def doQueryKEYST(self, cmd, args): + self.write("%d" % self.KEYST) + self.KEYST = 0 + def doQueryKRDG(self, cmd, args): + loop = ord(args[0]) - 64 + if loop < 1: + loop = 1 + if loop > 4: + loop = 4 + self.write("%f" % (self.KRDG[loop] + self.RANDOM)) + def doQueryLDAT(self, cmd, args): + self.write("3.000E+02") # TODO + print "TODO implement Query: \"LDAT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLINEAR(self, cmd, args): + self.write("1,1.0,1,3") # TODO + print "TODO implement Query: \"LINEAR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandLINEAR(self, cmd, args): + print "Unimplemented Command: \"LINEAR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLOCK(self, cmd, args): + self.write("%s" % self.LOCK) + def doCommandLOCK(self, cmd, args): + self.LOCK = args[0] + def doQueryMDAT(self, cmd, args): + response = "0" + if len(args[0]) > 0: + idx = int(args[0]) + if idx in self.MDAT: + (minv, maxv, reset) = self.MDAT[idx].split(",") + response = "%f,%f" % (float(minv), float(maxv)) + self.write(response) + def doQueryMNMX(self, cmd, args): + self.write("1") # TODO + print "TODO implement Query: \"MNMX?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMX(self, cmd, args): + print "Unimplemented Command: \"MNMX\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMXRST(self, cmd, args): + print "Unimplemented Command: \"MNMXRST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMODE(self, cmd, args): + print "Unimplemented Query: \"MODE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMODE(self, cmd, args): + print "Unimplemented Command: \"MODE\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMONITOR(self, cmd, args): + print "Unimplemented Query: \"MONITOR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMONITOR(self, cmd, args): + print "Unimplemented Command: \"MONITOR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMOUT(self, cmd, args): + idx = int(args[0]) + self.write(self.MOUT[idx]) + def doCommandMOUT(self, cmd, args): + print "Unimplemented Command: \"MOUT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryPID(self, cmd, args): + idx = int(args[0]) + self.write(self.PID[idx]) + def doCommandPID(self, cmd, args): + print "Unimplemented Command: \"PID\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRANGE(self, cmd, args): + idx = 1 + self.write(self.RANGE[idx]) + def doCommandRANGE(self, cmd, args): + idx = 1 + val = int(args[0]) + self.RANGE[idx] = val + def doQueryRAMP(self, cmd, args): + idx = int(args[0]) + response = "%d,%f" % (self.RAMP_ON[idx], self.RAMP_RATE[idx]) + self.write(response) + def doCommandRAMP(self, cmd, args): + idx = int(args[0]) + ramp_on = int(args[1]) + if ramp_on == 0 or ramp_on == 1: + self.RAMP_ON[idx] = ramp_on + if ramp_on == 1: + ramp_rate = float(args[2]) + if ramp_rate >= 0.001 and ramp_rate <= 100.0: + self.RAMP_RATE[idx] = ramp_rate + def doQueryRAMPST(self, cmd, args): + idx = int(args[0]) + response = "%d" % self.RAMP_ST[idx] + self.write(response) + def doQueryRDGPWR(self, cmd, args): + self.write("1.000E-15") # TODO + print "TODO implement Query: \"RDGPWR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGR(self, cmd, args): + self.write("1.000E+03") # TODO + print "TODO implement Query: \"RDGR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGRNG(self, cmd, args): + self.write("1,1,19,0,0") # TODO + print "TODO implement Query: \"RDGRNG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandRDGRNG(self, cmd, args): + print "Unimplemented Command: \"RDGRNG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGST(self, cmd, args): + self.write("000") + print "TODO implement Query: \"RDGST?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRELAY(self, cmd, args): + idx = int(args[0]) + self.write(self.RELAY[idx]) + def doCommandRELAY(self, cmd, args): + idx = int(args[0]) + if idx in self.RELAY: + self.relay[idx] = ",".join(args[1:]) + def doQueryRELAYST(self, cmd, args): + idx = int(args[0]) + self.write(self.RELAYST[idx]) + def doQuerySETP(self, cmd, args): + idx = int(args[0]) + val = self.SETP[idx] + self.write("%f" % val) + def doCommandSETP(self, cmd, args): + idx = int(args[0]) + val = float(args[1]) + if (val >= 0.0 and val <= 500.0): + self.TARGET[idx] = val + if self.RAMP_ON[idx] == 0: + self.SETP[idx] = val + self.RAMP_ST[idx] = 0 + else: + self.RAMP_START_TEMP[idx] = self.SETP[idx] + self.RAMP_START_TIME[idx] = time.time() + self.RAMP_ST[idx] = 1 + def doQuerySETTLE(self, cmd, args): + self.write(self.SETTLE) + def doCommandSETTLE(self, cmd, args): + self.SETTLE = ",".join(args) + def doQueryZONE(self, cmd, args): + print "Unimplemented Query: \"ZONE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandZONE(self, cmd, args): + print "Unimplemented Command: \"ZONE\" in \"" + cmd + " " + ",".join(args) + "\"" + +if __name__ == '__main__': + from LakeshoreProtocol import LakeshoreProtocol + + class TestFactory: + def __init__(self): + print self.__class__.__name__, "ctor" + self.numProtocols = 0 + def write(self, data): + print "test write:", data, + def loseConnection(self): + print "test lose connection" + test_factory = TestFactory() + test_device = Lakeshore340() + test_protocol = LakeshoreProtocol(test_device, "\r\n") + test_protocol.factory = test_factory + test_protocol.transport = test_factory + test_device.protocol = test_protocol + test_device.protocol.connectionMade() + test_device.protocol.dataReceived("*IDN?") + test_device.protocol.dataReceived("*TST?") + test_device.protocol.connectionLost("Dunno") diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore370.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore370.py new file mode 100755 index 00000000..61d0dd0c --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/Lakeshore370.py @@ -0,0 +1,472 @@ +# vim: ts=8 sts=4 sw=4 expandtab +# Fake Lakeshore Model 370 Temperature Controller +# +# Author: Douglas Clowes 2012, 2013 +# +from LakeshoreDevice import LakeshoreDevice +import random +import re +import sys +import time + +class Lakeshore370(LakeshoreDevice): + """Lakeshore 370 temperature controller object - simulates the LS370""" + + def __init__(self): + LakeshoreDevice.__init__(self) + print Lakeshore370.__name__, "ctor" + self.CONFIG_LOOPS = [1] + self.CONFIG_SNSRS = [i for i in range(1,17)] + self.reset_powerup() + + def doCommand(self, command, params): + print Lakeshore370.__name__, "Command:", command, params + return LakeshoreDevice.doCommand(self, command, params) + + def doQuery(self, command, params): + print Lakeshore370.__name__, "Query:", command, params + return LakeshoreDevice.doQuery(self, command, params) + + def reset_powerup(self): + print Lakeshore370.__name__, "reset_powerup" + self.LAST_ITERATION = 0 + self.ALARM = {1: "0,1,500.0,0.0,0,0"} + self.ALARMST = {1: "0,0"} + self.ANALOG = {1: "0,1,1,1,400.0,0.0,0.0", 2: "0,1,1,1,400.0,0.0,0.0"} + self.AOUT = { 1: 0.0, 2: 0.0 } + self.CMODE = {} + for idx in self.CONFIG_LOOPS: + self.CMODE[idx] = 1 + self.CMR = 0 + self.CPOL = 0 + self.CRVHDR = {} + self.CRVHDR[1] = "DT-336-1 ,STANDARD ,1,+500.000,1" + self.CRVHDR[2] = "DT-336-2 ,STANDARD ,2,+0.500,1" + self.CRVHDR[3] = "DT-336-3 ,STANDARD ,3,+2.000,2" + self.CRVHDR[4] = "DT-336-4 ,STANDARD ,4,+0.301,2" + self.CRVPT = {} + for i in range(1,21): + self.CRVPT[i] = [(0.0, 0.0)] + self.CSET = "1,0,1,30,1,8,100" + self.DOUT = 0 + self.FILTER = {1: "1,10,2"} + self.FREQ = 2 + self.GUARD = 0 + self.HTR = 0.0 + self.HTRRNG = 0 + self.HTRST = 0 + self.IDN = "LSCI,MODEL370,123456,00000000,1.5" + self.IEEE = "0,0,4" + self.INCRV = {} + self.INSET = {} + for idx in self.CONFIG_SNSRS: + self.INCRV[idx] = "1" + self.INSET[idx] = "1,10,3,0,2" + self.INTYPE = {"A": "1,0,1,0,1", "B": "1,0,1,0,1", "C": "1,0,1,0,1", "D": "1,0,1,0,1" } + self.KEYST = 1 + self.KRDG = {} + for idx in self.CONFIG_SNSRS: + self.KRDG[idx] = 300.0 + self.LOCK = "0,000" + self.MDAT = {1: "0,0,1"} # Min,Max,Reset + self.MOUT = {1: "0.0", 2: "0.0", 3: "0.0", 4: "0.0"} + self.OUTMODE = {1: "1,1,0", 2: "1,2,0", 3: "1,3,0", 4: "1,4,0"} + self.PID = {1: "+0150.0,+0005.0,+000.0", 2: "+0150.0,+0005.0,+000.0"} + self.RAMP_ON = {1: 0} + self.RAMP_RATE = {1: 0.000} + self.RAMP_ST = {1: 0} + self.RAMP_TIME = 0.0 + self.RDGST = {"A": 0, "B": 0, "C": 0, "D": 0} + self.RELAY = {1: "1,A,0", 2: "2,A,0"} + self.RELAYST = {1: "0", 2: "0"} + self.SETP = {} + self.TARGET = {} + self.RAMP_START_TEMP = {} + self.RAMP_START_TIME = {} + for idx in self.CONFIG_LOOPS: + self.SETP[idx] = 300.0 + self.TARGET[idx] = 300.0 + self.RAMP_START_TEMP[idx] = 300.0 + self.RAMP_START_TIME[idx] = 0.0 + self.STB = 0 + self.ESE = 0 + self.ESR = 0 + self.OPC = 0 + self.SRE = 0 + self.TST = 0 + self.RANDOM = 0.5 + + def doIteration(self): + delta_time = time.time() - self.LAST_ITERATION + if delta_time < 1: + return + #print "DoIteration:", delta_time + self.LAST_ITERATION = time.time() + for idx in self.CONFIG_LOOPS: + # TODO - progress ramping setpoints (SP) + if idx in self.RAMP_ON and self.RAMP_ON[idx] and self.TARGET[idx] != self.SETP[idx]: + delta_time = time.time() - self.RAMP_START_TIME[idx]; + delta_temp = self.RAMP_RATE[idx] * (delta_time / 60.0) + if self.TARGET[idx] > self.RAMP_START_TEMP[idx]: + self.SETP[idx] = self.RAMP_START_TEMP[idx] + delta_temp + if self.SETP[idx] >= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + else: + self.SETP[idx] = self.RAMP_START_TEMP[idx] - delta_temp + if self.SETP[idx] <= self.TARGET[idx]: + self.SETP[idx] = self.TARGET[idx] + self.RAMP_ST[idx] = 0 + + # TODO - iterate Power Level + if self.KRDG[idx] <> self.SETP[idx]: + self.HTR = self.SETP[idx] - self.KRDG[idx] + if self.HTR > 100.0: + self.HTR = 100.0 + elif self.HTR < -100.0: + self.HTR = -100.0 + + # TODO - iterate Process Values (PV) + self.KRDG[idx] = (0.9 * self.KRDG[idx] + 0.1 * self.SETP[idx]) + + def doCommandCLS(self, cmd, args): + print "Unimplemented Command: \"*CLS\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandESE(self, cmd, args): + self.ESE = int(args[0]) & 0xFF + def doQueryESE(self, cmd, args): + self.write("%d" % self.ESE) + def doQueryESR(self, cmd, args): + self.write("%d" % self.ESR) + def doQueryIDN(self, cmd, args): + self.write(self.IDN) + def doCommandOPC(self, cmd, args): + self.OPC = 1 + def doQueryOPC(self, cmd, args): + self.write("1") + def doCommandRST(self, cmd, args): + print "Unimplemented Command: \"*RST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandSRE(self, cmd, args): + self.SRE = int(args[0]) & 0xFF + def doQuerySRE(self, cmd, args): + self.write("%d" % self.SRE) + def doQuerySTB(self, cmd, args): + self.write("%d" % self.STB) + def doQueryTST(self, cmd, args): + self.write("%d" % self.TST) + def doCommandWAI(self, cmd, args): + print "Unimplemented Command: \"*WAI\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandALARM(self, cmd, args): + if len(args) > 0: + if int(args[0]) in self.ALARM: + keys = [int(args)] + else: + keys = self.ALARM.keys() + params = args[1:].join(",") + for key in keys: + self.ALARM[key] = params + def doQueryALARM(self, cmd, args): + idx = int(args[0]) + if idx in self.ALARM: + self.write(self.ALARM[idx]) + else: + self.write("0,1,500.0,0.0,0") + def doQueryALARMST(self, cmd, args): + idx = int(args[0]) + if idx in self.ALARMST: + self.write(self.ALARMST[idx]) + else: + self.write("0,0") + def doCommandALMRST(self, cmd, args): + for key in self.ALARMST.keys(): + self.ALARMST[key] = "0,0" + def doCommandANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.ANALOG[key] = ",".join(args[1:]) + print "TODO implement Command: \"ANALOG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryANALOG(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write(self.ANALOG[key]) # TODO + print "TODO implement Query: \"ANALOG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryAOUT(self, cmd, args): + key = args[0] + if key < 1 or key > 2: + key = 1 + self.write("%6.3f" % self.AOUT[key]) # TODO + print "TODO implement Query: \"AOUT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandBAUD(self, cmd, args): + print "Unimplemented Command: \"BAUD\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBAUD(self, cmd, args): + print "Unimplemented Query: \"BAUD?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandBEEP(self, cmd, args): + print "Unimplemented Command: \"BEEP\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBEEP(self, cmd, args): + print "Unimplemented Query: \"BEEP?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandBRIGT(self, cmd, args): + print "Unimplemented Command: \"BRIGT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryBRIGT(self, cmd, args): + print "Unimplemented Query: \"BRIGT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCHGALL(self, cmd, args): + print "Unimplemented Command: \"CHGALL\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCHGALL(self, cmd, args): + print "Unimplemented Query: \"CHGALL?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCMODE(self, cmd, args): + loop = 1 + if loop in self.CMODE: + self.CMODE[loop] = int(args[0]) + def doQueryCMODE(self, cmd, args): + loop = 1 + if loop in self.CMODE: + self.write("%f" % self.CMODE[loop]) + def doCommandCMR(self, cmd, args): + self.CMR = int(args[0]) + def doQueryCMR(self, cmd, args): + self.write("%d" % self.CMR) + def doCommandCPOL(self, cmd, args): + self.CPOL = int(args[0]) + def doQueryCPOL(self, cmd, args): + self.write("%d" % self.CPOL) + def doCommandCRVDEL(self, cmd, args): + print "Unimplemented Command: \"CRVDEL\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVHDR(self, cmd, args): + print "Unimplemented Command: \"CRVHDR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVHDR(self, cmd, args): + key = int(args[0]) + if key in self.CRVHDR: + self.write(self.CRVHDR[key]) + else: + self.write("DT-336-1 ,STANDARD ,1,+500.000,1") # TODO + print "TODO implement Query: \"CRVHDR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + # TODO set the Curve Point + print "TODO implement Command: \"CRVPT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryCRVPT(self, cmd, args): + key = int(args[0]) + if key < 1 or key > 20: + key = 1 + idx = int(args[1]) + if idx < 1 or idx > 200: + idx = 1 + self.write("1.0E+01,1.0+E02") # TODO + print "TODO implement Query: \"CRVPT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandCSET(self, cmd, args): + self.CSET = args[0] + def doQueryCSET(self, cmd, args): + self.write("%s" % self.CSET) + def doCommandDFLT(self, cmd, args): + if args[0] == "99": + print "Unimplemented Command: \"DFLT 99\" in \"" + cmd + " " + ",".join(args) + "\"" + else: + print "Invalid Command: \"DFLT " + args[0] + "\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLAY(self, cmd, args): + print "Unimplemented Command: \"DISPLAY\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLAY(self, cmd, args): + print "Unimplemented Query: \"DISPLAY?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDISPLOC(self, cmd, args): + print "Unimplemented Command: \"DISPLOC\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryDISPLOC(self, cmd, args): + print "Unimplemented Query: \"DISPLOC?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandDOUT(self, cmd, args): + self.DOUT = int(args[0]) + def doQueryDOUT(self, cmd, args): + self.write("%d" % self.DOUT) + def doCommandFILTER(self, cmd, args): + if len(args) > 0: + if int(args[0]) in self.FILTER: + keys = [int(args)] + else: + keys = self.FILTER.keys() + params = args[1:].join(",") + for key in keys: + self.FILTER[key] = params + def doQueryFILTER(self, cmd, args): + idx = int(args[0]) + if idx in self.FILTER: + self.write(self.FILTER[idx]) + else: + self.write("0") + def doCommandFREQ(self, cmd, args): + self.FREQ = int(args[0]) + def doQueryFREQ(self, cmd, args): + self.write("%d" % self.FREQ) + def doCommandGUARD(self, cmd, args): + self.GUARD = int(args[0]) + def doQueryGUARD(self, cmd, args): + self.write("%d" % self.GUARD) + def doQueryHTR(self, cmd, args): + self.write("%f" % self.HTR) + def doCommandHTRRNG(self, cmd, args): + self.HTRRNG = int(args[0]) + def doQueryHTRRNG(self, cmd, args): + self.write("%d" % self.HTRRNG) + def doQueryHTRST(self, cmd, args): + self.write("%d" % self.HTRST) + def doQueryIEEE(self, cmd, args): + self.write("%s" % self.IEEE) + def doCommandIEEE(self, cmd, args): + self.IEEE = args[0] + def doQueryINSET(self, cmd, args): + idx = int(args[0]) + if idx in self.INSET: + self.write(self.INSET[idx]) + else: + self.write("0") + def doCommandINSET(self, cmd, args): + if len(args) > 0: + idx = int(args[0]) + if idx in self.INSET: + params = ",".join(args[1:]) + self.INSET[idx] = params + def doQueryKEYST(self, cmd, args): + self.write("%d" % self.KEYST) + self.KEYST = 0 + def doQueryLDAT(self, cmd, args): + self.write("3.000E+02") # TODO + print "TODO implement Query: \"LDAT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLINEAR(self, cmd, args): + self.write("1,1.0,1,3") # TODO + print "TODO implement Query: \"LINEAR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandLINEAR(self, cmd, args): + print "Unimplemented Command: \"LINEAR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryLOCK(self, cmd, args): + self.write("%s" % self.LOCK) + def doCommandLOCK(self, cmd, args): + self.LOCK = args[0] + def doQueryMDAT(self, cmd, args): + response = "0" + if len(args[0]) > 0: + idx = int(args[0]) + if idx in self.MDAT: + (minv, maxv, reset) = self.MDAT[idx].split(",") + response = "%f,%f" % (float(minv), float(maxv)) + self.write(response) + def doQueryMNMX(self, cmd, args): + self.write("1") # TODO + print "TODO implement Query: \"MNMX?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMX(self, cmd, args): + print "Unimplemented Command: \"MNMX\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMNMXRST(self, cmd, args): + print "Unimplemented Command: \"MNMXRST\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMODE(self, cmd, args): + print "Unimplemented Query: \"MODE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMODE(self, cmd, args): + print "Unimplemented Command: \"MODE\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMONITOR(self, cmd, args): + print "Unimplemented Query: \"MONITOR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMONITOR(self, cmd, args): + print "Unimplemented Command: \"MONITOR\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryMOUT(self, cmd, args): + print "Unimplemented Query: \"MOUT?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandMOUT(self, cmd, args): + print "Unimplemented Command: \"MOUT\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryPID(self, cmd, args): + idx = int(args[0]) + self.write(self.PID[idx]) + def doCommandPID(self, cmd, args): + print "Unimplemented Command: \"PID\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRAMP(self, cmd, args): + idx = 1 + response = "%d,%f" % (self.RAMP_ON[idx], self.RAMP_RATE[idx]) + self.write(response) + def doCommandRAMP(self, cmd, args): + idx = 1 + ramp_on = int(args[0]) + if ramp_on == 0 or ramp_on == 1: + self.RAMP_ON[idx] = ramp_on + if ramp_on == 1: + ramp_rate = float(args[1]) + if ramp_rate >= 0.001 and ramp_rate <= 10.0: + self.RAMP_RATE[idx] = ramp_rate + def doQueryRAMPST(self, cmd, args): + response = "%d" % self.RAMP_ST + self.write(response) + def doQueryRDGK(self, cmd, args): + if len(args) == 0 or len(args[0]) == 0: + idx = 1 + else: + idx = int(args[0]) + if idx in self.KRDG: + self.RANDOM = random.uniform(-0.5, 0.5) + self.RANDOM = 0.5 + self.write("%f" % (self.KRDG[idx] + self.RANDOM)) + else: + self.write("+000.0") + def doQueryRDGPWR(self, cmd, args): + self.write("1.000E-15") # TODO + print "TODO implement Query: \"RDGPWR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGR(self, cmd, args): + self.write("1.000E+03") # TODO + print "TODO implement Query: \"RDGR?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGRNG(self, cmd, args): + self.write("1,1,19,0,0") # TODO + print "TODO implement Query: \"RDGRNG?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandRDGRNG(self, cmd, args): + print "Unimplemented Command: \"RDGRNG\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRDGST(self, cmd, args): + self.write("000") + print "TODO implement Query: \"RDGST?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRELAY(self, cmd, args): + print "Unimplemented Query: \"RELAY?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandRELAY(self, cmd, args): + print "Unimplemented Command: \"RELAY\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryRELAYST(self, cmd, args): + print "Unimplemented Query: \"RELAYST?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQuerySCAN(self, cmd, args): + print "Unimplemented Query: \"SCAN?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandSCAN(self, cmd, args): + print "Unimplemented Command: \"SCAN\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQuerySETP(self, cmd, args): + idx = 1 + val = self.SETP[idx] + self.write("%f" % val) + def doCommandSETP(self, cmd, args): + idx = 1 + val = float(args[0]) + if (val >= 0.0 and val <= 500.0): + self.TARGET[idx] = val + if self.RAMP_ON[idx] == 0: + self.SETP[idx] = val + self.RAMP_ST[idx] = 0 + else: + self.RAMP_START_TEMP[idx] = self.SETP[idx] + self.RAMP_START_TIME[idx] = time.time() + self.RAMP_ST[idx] = 1 + def doQuerySTILL(self, cmd, args): + print "Unimplemented Query: \"STILL?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandSTILL(self, cmd, args): + print "Unimplemented Command: \"STILL\" in \"" + cmd + " " + ",".join(args) + "\"" + def doQueryZONE(self, cmd, args): + print "Unimplemented Query: \"ZONE?\" in \"" + cmd + " " + ",".join(args) + "\"" + def doCommandZONE(self, cmd, args): + print "Unimplemented Command: \"ZONE\" in \"" + cmd + " " + ",".join(args) + "\"" + +if __name__ == '__main__': + from LakeshoreProtocol import LakeshoreProtocol + + class TestFactory: + def __init__(self): + print self.__class__.__name__, "ctor" + self.numProtocols = 0 + def write(self, data): + print "test write:", data, + def loseConnection(self): + print "test lose connection" + test_factory = TestFactory() + test_device = Lakeshore370() + test_protocol = LakeshoreProtocol(test_device, "\r\n") + test_protocol.factory = test_factory + test_protocol.transport = test_factory + test_device.protocol = test_protocol + test_device.protocol.connectionMade() + test_device.protocol.dataReceived("*IDN?") + test_device.protocol.dataReceived("*TST?") + test_device.protocol.connectionLost("Dunno") diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreDevice.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreDevice.py new file mode 100755 index 00000000..4e739c8d --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreDevice.py @@ -0,0 +1,92 @@ +# vim: ts=8 sts=4 sw=4 expandtab +# +# Generic Lakeshore Temperature Controller Device +# +# Author: Douglas Clowes (2013) +# +import inspect +import traceback + +class LakeshoreDevice(object): + + def __init__(self): + print LakeshoreDevice.__name__, "ctor" + #print "Methods:", inspect.getmembers(self, inspect.ismethod) + methods = inspect.getmembers(self, inspect.ismethod) + self.myMethods = {} + for method in methods: + self.myMethods[method[0]] = method[1:] + #for method in sorted(self.myMethods): + # print "Method:", method, self.myMethods[method], type(method), type(self.myMethods[method]) + + def reset_powerup(self): + print LakeshoreDevice.__name__, "reset_powerup" + + def write(self, response): + print "Device Response: %s" % response + self.protocol.write(response) + + def doCommand(self, command, params): + print LakeshoreDevice.__name__, "Command:", command, params + method = "doCommand%s" % command + if method in self.myMethods: + action = "response = self.%s(command, params)" % method + print "Action:", action + exec action + if response: + return response + else: + print "Unimplemented Command:", command, params + return False + + def doQuery(self, command, params): + print LakeshoreDevice.__name__, "Query:", command, params + method = "doQuery%s" % command + if method in self.myMethods: + action = "response = self.%s(command, params)" % method + print "Action:", action + exec action + if response: + return response + else: + print "Unimplemented Query:", command, params + self.write("Unimplemented Query: %s" % command) + return False + + def doQueryTST(self, command, params): + self.write("0") + return True + + def doQueryIDN(self, command, params): + self.write(self.IDN) + return True + + def dataReceived(self, data): + print LakeshoreDevice.__name__, "PDU: \"" + data + "\"" + command = data.split()[0] + params = data[len(command):].strip().split(",") + if command[0] == "*": + command = command[1:] + try: + if command[-1] == '?': + self.doQuery(command[:-1], params) + else: + self.doCommand(command, params) + except: + traceback.print_exc() + +if __name__ == '__main__': + class TestProtocol: + def __init__(self): + print self.__class__.__name__, "ctor" + self.numProtocols = 0 + def write(self, data): + print "test write:", data + def loseConnection(self): + print "test lose connection" + test_protocol = TestProtocol() + test_device = LakeshoreDevice() + test_device.protocol = test_protocol + test_device.dataReceived("*IDN?") + test_device.dataReceived("*TST?") + test_device.dataReceived("RDGK?") diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreFactory.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreFactory.py new file mode 100644 index 00000000..89e60352 --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreFactory.py @@ -0,0 +1,43 @@ +# vim: ts=8 sts=4 sw=4 expandtab +from twisted.internet.protocol import ServerFactory + +class LakeshoreFactory(ServerFactory): + """Factory object used by the Twisted Infrastructure to create a Protocol + object for incomming connections""" + + protocol = None + + def __init__(self, theProtocol, theDevice, theTerminator = "\r\n"): + print LakeshoreFactory.__name__, "ctor" + self.protocol = theProtocol + self.device = theDevice + self.term = theTerminator + self.numProtocols = 0 + + def buildProtocol(self, addr): + p = self.protocol(self.device, self.term) + p.factory = self + return p + +if __name__ == '__main__': + class TestProtocol: + def __init__(self, theDevice, theTerm = "\r\n"): + self.device = theDevice + self.response = "" + self.term = theTerm + + class TestDevice: + def __init__(self): + pass + + new_factory = LakeshoreFactory(TestProtocol, TestDevice, "\r\n"); + new_protocol = new_factory.buildProtocol("address") + print "Factory: ", new_factory + print " .protocol", new_factory.protocol + print " .device ", new_factory.device + print " .num_prot", new_factory.numProtocols + print " .term ", new_factory.term + print "Protocol: ", new_protocol + print " .device ", new_protocol.device + print " .response", new_protocol.response + print " .term ", new_protocol.term diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreProtocol.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreProtocol.py new file mode 100755 index 00000000..23ea9a44 --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/LakeshoreProtocol.py @@ -0,0 +1,88 @@ +# vim: ts=8 sts=4 sw=4 expandtab +from twisted.internet.protocol import Protocol + +class LakeshoreProtocol(Protocol): + """Protocol object used by the Twisted Infrastructure to handle connections""" + + def __init__(self, theDevice, theTerminator = "\r\n"): + print LakeshoreProtocol.__name__, "ctor" + self.device = theDevice + self.response = "" + self.term = theTerminator + + def write(self, response): + self.response = self.response + response + + def connectionMade(self): + self.pdu = "" + self.response = "" + self.device.protocol = self + self.factory.numProtocols = self.factory.numProtocols + 1 + print "connectionMade:", self.factory.numProtocols + if self.factory.numProtocols > 2: + print "Too many connections - rejecting" + self.transport.write("Too many connections, try later" + self.term) + self.transport.loseConnection() + else: + self.transport.write(("Welcome connection %d" % self.factory.numProtocols) + self.term) + + def connectionLost(self, reason): + print "connectionLost:", self.factory.numProtocols, reason + self.factory.numProtocols = self.factory.numProtocols - 1 + + def lineReceived(self, data): + print "lineReceived - len:", len(data), data + self.device.protocol = self + self.device.dataReceived(data) + + def dataReceived(self, data): + print "dataReceived - len:", len(data), data + for c in data: + if c == "\r" or c == ";" or c == "\n": + if len(self.pdu) > 0: + self.lineReceived(self.pdu) + self.pdu = "" + if c == ";": + if len(self.response) > 0 and self.response[-1] != ";": + self.response = self.response + ";" + else: + if len(self.response) > 0: + if self.response[-1] == ";": + self.response = self.response[:-1] + if len(self.response) > 0: + print "Protocol Response: %s" % self.response + self.transport.write(self.response + self.term) + self.response = "" + else: + self.pdu = self.pdu + c + +if __name__ == '__main__': + class TestDevice: + def __init__(self): + print self.__class__.__name__, "ctor" + def dataReceived(self, pdu): + print "test device data received:", pdu + self.protocol.write("test device response") + class TestFactory: + def __init__(self): + self.numProtocols = 0 + def write(self, data): + print "test write:", data, + def loseConnection(self): + print "test lose connection" + self.protocol.connectionLost("Factory") + myTerm = "\r\n" + test_device = TestDevice() + test_factory = TestFactory() + test_protocol = LakeshoreProtocol(test_device, myTerm) + test_factory.protocol = test_protocol + test_protocol.factory = test_factory + test_protocol.transport = test_factory + test_protocol.connectionMade() + test_protocol.connectionMade() + test_protocol.connectionMade() + test_protocol.connectionLost("Dunno") + test_protocol.dataReceived("*IDN?" + myTerm + "*IDN?;*I") + test_protocol.dataReceived("DN") + test_protocol.dataReceived("?" + myTerm) + test_protocol.connectionLost("Dunno") diff --git a/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/displayscreen.py b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/displayscreen.py new file mode 100644 index 00000000..137f93de --- /dev/null +++ b/site_ansto/instrument/TEST_SICS/fakeTempControl/lakeshore/displayscreen.py @@ -0,0 +1,150 @@ +# vim: ts=8 sts=4 sw=4 expandtab + +import curses + +class CursesStdIO: + """fake fd to be registered as a reader with the twisted reactor. + Curses classes needing input should extend this""" + + def fileno(self): + """ We want to select on FD 0 """ + return 0 + + def doRead(self): + """called when input is ready""" + + def logPrefix(self): return 'CursesClient' + +class Screen(CursesStdIO): + def __init__(self, stdscr): + self.timer = 0 + self.statusText = "TEST CURSES APP -" + self.searchText = '' + self.stdscr = stdscr + + # set screen attributes + self.stdscr.nodelay(1) # this is used to make input calls non-blocking + curses.cbreak() + self.stdscr.keypad(1) + curses.curs_set(0) # no annoying mouse cursor + + self.rows, self.cols = self.stdscr.getmaxyx() + self.lines = [] + + curses.start_color() + + # create color pair's 1 and 2 + curses.init_pair(1, curses.COLOR_BLACK, curses.COLOR_WHITE) + curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK) + + self.paintStatus(self.statusText) + self.stdscr.refresh() + + def connectionLost(self, reason): + self.close() + + def addLine(self, text): + """ add a line to the internal list of lines""" + + self.lines.append(text) + while len(self.lines) > 10: + del self.lines[0] + self.redisplayLines() + + def redisplayLines(self): + """ method for redisplaying lines + based on internal list of lines """ + + self.stdscr.clear() + self.paintStatus(self.statusText) + i = 0 + index = len(self.lines) - 1 + while i < (self.rows - 3) and index >= 0: + self.stdscr.addstr(self.rows - 3 - i, 0, self.lines[index], + curses.color_pair(2)) + i = i + 1 + index = index - 1 + self.stdscr.refresh() + + def paintStatus(self, text): + if len(text) > self.cols: raise TextTooLongError + self.stdscr.addstr(self.rows-2,0,text + ' ' * (self.cols-len(text)), + curses.color_pair(1)) + # move cursor to input line + self.stdscr.move(self.rows-1, self.cols-1) + + def doRead(self): + """ Input is ready! """ + curses.noecho() + self.timer = self.timer + 1 + c = self.stdscr.getch() # read a character + + if c == curses.KEY_BACKSPACE: + print "curses KEY_BACKSPACE" + self.searchText = self.searchText[:-1] + + elif c == curses.KEY_ENTER or c == 10: + self.addLine(self.searchText) + # for testing too + try: self.sendLine(self.searchText) + except: pass + self.stdscr.refresh() + self.searchText = '' + + elif c == curses.KEY_RESIZE: + print "curses KEY_RESIZE" + self.rows, self.cols = self.stdscr.getmaxyx() + self.redisplayLines() + self.paintStatus(self.statusText) + self.stdscr.refresh() + + elif c >= curses.KEY_MIN and c <= curses.KEY_MAX: + return + + else: + if len(self.searchText) >= self.cols-2: + return + self.searchText = self.searchText + chr(c) + + self.stdscr.addstr(self.rows-1, 0, + self.searchText + (' ' * ( + self.cols-len(self.searchText)-2))) + self.stdscr.move(self.rows-1, len(self.searchText)) + self.paintStatus(self.statusText + ' %d' % len(self.searchText)) + self.stdscr.refresh() + + def sendLine(self, txt): + pass + + def close(self): + """ clean up """ + + curses.nocbreak() + self.stdscr.keypad(0) + curses.echo() + curses.endwin() + +def device_display(): + global stdscr + try: + import datetime + now = datetime.datetime.now() + str = now.date().isoformat() + " " + now.time().isoformat() + stdscr.addstr(12, 25, "Time: %s" % str) + except: + pass + stdscr.refresh() + +if __name__ == '__main__': + global stdscr + from twisted.internet.task import LoopingCall + from twisted.internet import reactor + from twisted.python import log + + log.startLogging(open("/tmp/displayscreen.log", "w")) + stdscr = curses.initscr() + screen = Screen(stdscr) + lc = LoopingCall(device_display) + lc.start(0.250) + reactor.addReader(screen) # add screen object as a reader to the reactor + reactor.run()