169 lines
5.2 KiB
Tcl
169 lines
5.2 KiB
Tcl
##
|
|
# @file sct_protek_common.tcl
|
|
# @brief Gets display state from Protek 608 multimeters.
|
|
#
|
|
# Author: Ferdi Franceschini (ffr@ansto.gov.au)
|
|
|
|
## MULTIMETER STATE FIELDS AND VALUES
|
|
###### MODES
|
|
# AUTOOFF:1/0 PULSE:1/0 MAX:1/0 PLUSPEAK:1/0 REL:1/0 RECALL:1/0 GO/NG:1/0 MINUSPER:1/0
|
|
# RS232C:1/0 PLUS:1/0 MINUS:1/0 MIN:1/0 MINUSPEAK:1/0 AVG:1/0 STORE:1/0 REF:1/0 PLUSPER:1/0
|
|
# LOBAT:1/0
|
|
|
|
###### MAIN DISPLAY
|
|
# AC1:1/0 SIGN1:1/0 DC1:1/0 PW1:1/0
|
|
# MD5:np MD4:np MD3:np MD2:np MD1:n
|
|
# M1:1/0 k1:1/0 OHM1:1/0
|
|
# u1:1/0 Hz1:1/0
|
|
# m1:1/0 V1:1/0 A1:1/0
|
|
# n1:1/0 S1:1/0 F1:1/0
|
|
# DEGC1:1/0 s1:1/0
|
|
# DEGF1:1/0
|
|
|
|
###### BAR GRAPH
|
|
# B16K:1/0 B8K:1/0 B4K:1/0 B2K:1/0 B1K:1/0
|
|
# B512:1/0 B256:1/0 B128:1/0 B64:1/0 B32:1/0
|
|
# B16:1/0 B8:1/0 B4:1/0 B2:1/0 B1:1/0 B0:1/0
|
|
|
|
###### SUB DISPLAY
|
|
# RANGE2:1/0 HOLD2:1/0 DUTY2:1/0
|
|
# CONT2:1/0 ZD2:1/0
|
|
# AC2:1/0 SIGN2:1/0 DC2:1/0
|
|
# SD5:np SD4:np SD3:np SD2:np SD1:n
|
|
# PERCENT2:1/0 dBm2:1/0
|
|
# m2:1/0 V2:1/0 A2:1/0 DEGK2:1/0
|
|
# G2:1/0 M2:1/0 k2:1/0 OHM2:1/0 Hz2:1/0
|
|
|
|
# ROTSWITCH:[0-8]
|
|
|
|
### The return values for nine bytes is undocumented,
|
|
### they are labelled as X1 to X9
|
|
# X[1-9]:?
|
|
|
|
##
|
|
# @brief Sends a state report request to the protek script context protocol handler.
|
|
proc rqStateRep {} {
|
|
sct send "STATE"
|
|
return rdStateRep
|
|
}
|
|
|
|
##
|
|
# @brief Processes state report from the protek script context protocol handler.
|
|
proc rdStateRep {} {
|
|
set stateRep [sct result]
|
|
if {[string match "ASCERR:*" $stateRep]} {
|
|
sct geterror $stateRep
|
|
# Setting oldval forces update and clears geterror on next call
|
|
sct oldval "UNKNOWN"
|
|
return idle
|
|
}
|
|
|
|
array set stateArr [split $stateRep "|:"]
|
|
if {$stateArr(AUTOOFF)} {
|
|
broadcast "PROTEK608:[sct] WARNING AUTO OFF IS ENABLED"
|
|
}
|
|
if {$stateArr(LOBAT)} {
|
|
broadcast "PROTEK608:[sct] LOW BATTERY WARNING"
|
|
}
|
|
if {$stateRep != [sct oldval]} {
|
|
sct update $stateRep
|
|
sct oldval $stateRep
|
|
}
|
|
return idle
|
|
}
|
|
|
|
proc rqVal {nextState} {
|
|
return $nextState
|
|
}
|
|
proc ProtekMainDisplay {protek nextState} {
|
|
if [catch {
|
|
set stateRep [hval $protek/state]
|
|
set MDpath [sct]
|
|
set parname [file tail $MDpath]
|
|
set scale [hval $MDpath/scale]
|
|
set offset [hval $MDpath/offset]
|
|
array set SA [split $stateRep "|:"]
|
|
if {$SA(SIGN1)} {
|
|
set sign1 "-"
|
|
} else {
|
|
set sign1 ""
|
|
}
|
|
set MDISP "$sign1$SA(MD5)$SA(MD4)$SA(MD3)$SA(MD2)$SA(MD1)"
|
|
if {[string is double $MDISP] == 0} {
|
|
error "Non-numeric reading ($MDISP) from Protek main display"
|
|
}
|
|
set MDISP [expr {$scale * $MDISP + $offset}]
|
|
set oldval [sct oldval]
|
|
if {$MDISP != $oldval} {
|
|
sct update $MDISP
|
|
sct oldval $MDISP
|
|
protek_debug_log $parname $MDISP
|
|
}
|
|
} msg ] {
|
|
return -code error "[info level 0]: $msg"
|
|
}
|
|
return $nextState
|
|
}
|
|
|
|
proc protek_debug_log {name args} {
|
|
set fd [open "/usr/local/sics/data/protek_$name.csv" a]
|
|
puts $fd "[clock format [clock seconds] -format "%d/%m/%Y, %T"], $args"
|
|
close $fd
|
|
}
|
|
##
|
|
# @brief Makes a state monitor object for the protek multimeter
|
|
#
|
|
# @param name, name of object which reports main display reading
|
|
# @param IP, IP address of protek moxa box
|
|
# @param PORT, port number for protek on moxa box
|
|
# @param scale, scales reading to physical units
|
|
# @param offset, offset for main display reading
|
|
# @param interval, polling interval in seconds (optional, default = 0.5seconds)
|
|
# @param cbFunc, this function will be called after the voltage reading has been updated
|
|
# NOTE: If the interval is negative then the multimeter will be polled on every cycle of
|
|
# the SICS task loop.
|
|
proc MakeProtek {name sctName {scale 1.0} {offset 0.0} {interval 0.5} {cbFunc "return idle"}} {
|
|
set catch_status [ catch {
|
|
set sctName "sct_$name"
|
|
set sobjName "$name"
|
|
set soState "so_state_$name"
|
|
clientput "MakeSICSObj $sobjName SCT_OBJECT"
|
|
MakeSICSObj $soState SCT_OBJECT
|
|
sicslist setatt $sobjName long_name $sobjName
|
|
|
|
hfactory /sics/$soState/state plain user text
|
|
hsetprop /sics/$soState/state read rqStateRep
|
|
hsetprop /sics/$soState/state rdStateRep rdStateRep
|
|
hsetprop /sics/$soState/state oldval "UNKNOWN"
|
|
hsetprop /sics/$sobjName read rqVal "reportVal"
|
|
hsetprop /sics/$sobjName reportVal ProtekMainDisplay /sics/$soState callBack
|
|
hsetprop /sics/$sobjName callBack $cbFunc
|
|
hfactory /sics/$sobjName/scale plain user float
|
|
hset /sics/$sobjName/scale $scale
|
|
hfactory /sics/$sobjName/offset plain user float
|
|
hset /sics/$sobjName/offset $offset
|
|
hsetprop /sics/$sobjName oldval "UNKNOWN"
|
|
|
|
sicslist setatt $sobjName klass sample
|
|
::scobj::hinitprops $sobjName
|
|
sicslist setatt $sobjName long_name $name
|
|
if {[SplitReply [environment_simulation]] == false} {
|
|
$sctName poll /sics/$soState/state $interval
|
|
$sctName poll /sics/$sobjName $interval
|
|
}
|
|
} catch_message ] {
|
|
handle_exception ${catch_status} ${catch_message}
|
|
}
|
|
return /sics/$sobjName
|
|
}
|
|
|
|
|
|
# proc add_protekmm {name IP PORT CTYPE CID {scale 1.0} {offset 0.0} {interval 0.5} {cbFunc "return idle"}} {
|
|
# set catch_status [ catch {
|
|
# MakeProtek $name $IP $PORT $scale $offset $interval $cbFunc
|
|
# hsetprop /sics/$name permlink data_set ${CTYPE}${CID}S1
|
|
# } catch_message ] {
|
|
# handle_exception ${catch_status} ${catch_message}
|
|
# }
|
|
# }
|