226 lines
5.7 KiB
Tcl
226 lines
5.7 KiB
Tcl
#
|
|
# Usage
|
|
# 1) source this file
|
|
# 2) define variables records, protocol, starup
|
|
# 3) call startioc
|
|
# 4) use ioccmd, assure, receive, send,...
|
|
# 5) call finish
|
|
|
|
set testname [file tail $argv0]
|
|
|
|
proc bgerror msg {
|
|
error $::errorInfo
|
|
}
|
|
|
|
set debug 0
|
|
proc debugmsg {string} {
|
|
global debug
|
|
if $debug {puts $string}
|
|
}
|
|
|
|
proc deviceconnect {s addr port} {
|
|
debugmsg "incoming connenction"
|
|
global sock
|
|
set sock $s
|
|
fconfigure $sock -blocking no -buffering none -translation binary
|
|
fileevent $sock readable "receiveHandler $sock"
|
|
}
|
|
|
|
set inputbuffer {}
|
|
proc receiveHandler {sock} {
|
|
global inputbuffer inputlog
|
|
set input [read $sock]
|
|
puts -nonewline $inputlog $input
|
|
append inputbuffer $input
|
|
debugmsg "receiving \"[escape $inputbuffer]\""
|
|
if [eof $sock] {
|
|
close $sock
|
|
debugmsg "connection closed by ioc"
|
|
return
|
|
}
|
|
}
|
|
|
|
proc startioc {} {
|
|
global debug records protocol startup port sock ioc testname env streamversion asynversion
|
|
set fd [open test.db w]
|
|
puts $fd $records
|
|
close $fd
|
|
set fd [open test.proto w]
|
|
puts $fd $protocol
|
|
close $fd
|
|
set fd [open test.cmd w 0777]
|
|
|
|
if [info exists streamversion] {
|
|
puts $fd "#!/usr/local/bin/iocsh"
|
|
if [info exists asynversion] {
|
|
puts $fd "require asyn,$asynversion"
|
|
}
|
|
puts $fd "require stream,$streamversion"
|
|
} else {
|
|
puts $fd "#!../O.$env(EPICS_HOST_ARCH)/streamApp"
|
|
puts $fd "dbLoadDatabase ../O.Common/streamApp.dbd"
|
|
puts $fd "streamApp_registerRecordDeviceDriver"
|
|
}
|
|
puts $fd "streamSetLogfile StreamDebug.log"
|
|
puts $fd "var streamDebug 1"
|
|
puts $fd "var streamError 1"
|
|
puts $fd "epicsEnvSet STREAM_PROTOCOL_PATH ."
|
|
puts $fd "drvAsynIPPortConfigure device localhost:$port"
|
|
if [info exists startup] {
|
|
puts $fd $startup
|
|
}
|
|
puts $fd "dbLoadRecords test.db"
|
|
puts $fd "iocInit"
|
|
puts $fd "dbl"
|
|
puts $fd "dbior stream 2"
|
|
close $fd
|
|
if [info exists streamversion] {
|
|
set ioc [open "|iocsh test.cmd >& $testname.ioclog 2>@stderr" w]
|
|
} else {
|
|
set ioc [open "|../O.$env(EPICS_HOST_ARCH)/streamApp test.cmd >& $testname.ioclog 2>@stderr" w]
|
|
}
|
|
fconfigure $ioc -blocking yes -buffering none
|
|
debugmsg "waiting to connect"
|
|
set timer [after 1000 {puts stderr "\033\[31;7mCannot start IOC.\033\[0m"; exit 1}]
|
|
vwait sock
|
|
after cancel $timer
|
|
}
|
|
|
|
set lastcommand ""
|
|
set line 0
|
|
proc ioccmd {command} {
|
|
global ioc
|
|
global lastcommand
|
|
global line
|
|
set lastcommand $command
|
|
set line 0
|
|
debugmsg "$command"
|
|
puts $ioc $command
|
|
}
|
|
|
|
proc process {record} {
|
|
ioccmd "dbpf $record.PROC 1"
|
|
}
|
|
|
|
proc put {record value} {
|
|
ioccmd "dbpf $record \"$value\""
|
|
}
|
|
|
|
proc send {string} {
|
|
global sock lastsent
|
|
set lastsent $string
|
|
puts -nonewline $sock $string
|
|
flush $sock
|
|
}
|
|
|
|
set timeout 5000
|
|
proc receive {} {
|
|
global inputbuffer timeoutid timeout
|
|
set timeoutid [after $timeout {
|
|
set inputbuffer {}
|
|
}]
|
|
if {$inputbuffer == {}} { vwait inputbuffer }
|
|
after cancel $timeoutid
|
|
if {$inputbuffer == {}} {
|
|
return -code error "Error in receive: timeout"
|
|
}
|
|
set index [string first "\n" $inputbuffer]
|
|
if {$index > -1} {
|
|
set input [string range $inputbuffer 0 $index]
|
|
set inputbuffer [string range $inputbuffer [expr $index+1] end]
|
|
} else {
|
|
set input $inputbuffer
|
|
set inputbuffer {}
|
|
}
|
|
return $input
|
|
}
|
|
|
|
set faults 0
|
|
proc assure {args} {
|
|
global faults
|
|
global lastcommand
|
|
global lastsent
|
|
global line
|
|
|
|
incr line
|
|
set input {}
|
|
for {set i 0} {$i < [llength $args]} {incr i} {
|
|
if [catch {lappend input [receive]} msg] {
|
|
puts stderr $msg
|
|
break
|
|
}
|
|
}
|
|
set notfound {}
|
|
foreach expected $args {
|
|
set index [lsearch -exact $input $expected]
|
|
if {$index > -1} {
|
|
set input [lreplace $input $index $index]
|
|
} else {
|
|
lappend notfound $expected
|
|
}
|
|
}
|
|
if {[llength $notfound] || [llength $input]} {
|
|
puts stderr "In command \"$lastcommand\""
|
|
if [info exists lastsent] {
|
|
puts stderr "last sent: \"[escape $lastsent]\""
|
|
}
|
|
}
|
|
foreach string $notfound {
|
|
puts stderr "Error in assure: line $line missing \"[escape $string]\""
|
|
}
|
|
foreach string $input {
|
|
puts stderr "Error in assure: got unexpected \"[escape $string]\""
|
|
}
|
|
if {[llength $notfound] || [llength $input]} {incr faults}
|
|
}
|
|
|
|
proc escape {string} {
|
|
set result ""
|
|
set length [string length $string]
|
|
for {set i 0} {$i < $length} {incr i} {
|
|
set c [string index $string $i]
|
|
scan $c %c n
|
|
if {$n == 13} {
|
|
append result "\\r"
|
|
} elseif {$n == 10} {
|
|
append result "\\n"
|
|
} elseif {$n < 32 || $n >= 127} {
|
|
append result [format "<%02x>" $n]
|
|
} else {
|
|
append result $c
|
|
}
|
|
}
|
|
return $result
|
|
}
|
|
|
|
proc finish {} {
|
|
global ioc timeout testname faults
|
|
set timeout 1000
|
|
while {![catch {set string [receive]}]} {
|
|
puts stderr "Error in finish: unexpected \"[escape $string]\""
|
|
incr faults
|
|
}
|
|
after 100
|
|
close $ioc
|
|
if $faults {
|
|
puts "\033\[31;7mTest failed.\033\[0m"
|
|
exit 1
|
|
}
|
|
puts "\033\[32mTest passed.\033\[0m"
|
|
eval file delete [glob -nocomplain test.*] StreamDebug.log $testname.ioclog
|
|
}
|
|
|
|
set port 40123
|
|
socket -server deviceconnect $port
|
|
set inputlog [open "test.inputlog" w]
|
|
|
|
# SLS style driver modules (optionally with version)
|
|
if {[lindex $argv 0] == "-sls"} {
|
|
set streamversion [lindex $argv 1]
|
|
set argv [lrange $argv 2 end]
|
|
}
|
|
if {[lindex $argv 0] == "-asyn"} {
|
|
set asynversion [lindex $argv 1]
|
|
set argv [lrange $argv 2 end]
|
|
}
|