In our line of duty (Test Automation) we came about to work with IT6834 (Programmable DC Power Supply). According to it’s Manual http://www.itechate.com/null/IT-DOC/IT6800-UM-EN.pdf , the remote operation commands should have a 26 HEX Bytes code.
After few attempts we got the following:
proc OpenCom {} {
global fh buff
set fh [open COM1: RDWR]
fconfigure $fh -blocking 0 -mode 9600,n,8,1 -translation binary -buffering full -eofchar {} -sysbuffer {4096 4096}
set buff ""
fileevent $fh readable GetInst
}
proc GetInst {} {
global fh buff
set w [read $fh]
binary scan $w H* a
append buff $a
}
proc CloseCom {} {
global fh
close $fh
global fh
}
proc IT6800 {cmd {par ""} } {
global fh buff
switch -exact -- $cmd {
rmt {set cmdH 20}
out {set cmdH 21}
vlt {set cmdH 23}
cur {set cmdH 24}
get {set cmdH 26}
}
switch -exact -- $par {
on {set parH 01}
off {set parH 00}
}
if {$cmd=="rmt" || $cmd=="out"} {
set st [list AA 00 $cmdH $parH 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
} elseif {$cmd=="vlt"} {
set mVlt [expr round([expr {1000 * $par}])]
set mVltH [format %.8X $mVlt]
regexp {(\w{2})(\w{2})(\w{2})(\w{2})} $mVltH - b7 b6 b5 b4
set st [list AA 00 $cmdH $b4 $b5 $b6 $b7 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
} elseif {$cmd=="cur"} {
set mCur [expr round([expr {1000 * $par}])]
set mCurH [format %.4X $mCur]
regexp {(\w{2})(\w{2})} $mCurH - b5 b4
set st [list AA 00 $cmdH $b4 $b5 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
} elseif {$cmd=="get"} {
set buff ""
set st [list AA 00 $cmdH 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00]
}
## checkSum calculation
set chs [format %.2X [expr {0}]]
for {set i 0} {$i<[llength $st]} {incr i} {
set ll [lindex $st $i]
set chs [format %.2X [expr "0x$chs + 0x$ll"]]
}
if {[string length $chs]>2} {
set chs [string range $chs 1 end]
}
lappend st $chs
set st [join $st ""]
set st1 [binary format H* $st]
puts -nonewline $fh $st1 ; flush $fh
set ret 0
if {$cmd=="get"} {
delay 1
set adr [string range $buff 2 3]
set cmd [string range $buff 4 5]
set b4 [string range $buff 6 7]
set b5 [string range $buff 8 9]
set prH [set b5][set b4]
set prD1 [expr {[scan $prH %x]/1000.0}]
puts "Present Output Current:$prD1"
set b6 [string range $buff 10 11]
set b7 [string range $buff 12 13]
set b8 [string range $buff 14 15]
set b9 [string range $buff 16 17]
set prH [set b9][set b8][set b7][set b6]
set prD2 [expr {[scan $prH %x]/1000.0}]
puts "Present Output Voltage:$prD2"
set b11 [string range $buff 20 21]
set b12 [string range $buff 22 23]
set prH [set b12][set b11]
set prD3 [expr {[scan $prH %x]/1000.0}]
puts "Current:$prD3"
set b17 [string range $buff 32 33]
set b18 [string range $buff 34 35]
set b19 [string range $buff 36 37]
set b20 [string range $buff 38 39]
set prH [set b20][set b19][set b18][set b17]
set prD4 [expr {[scan $prH %x]/1000.0}]
puts "Voltage:$prD4"
set ret [set prD1]_[set prD2]_[set prD3]_[set prD4]
}
return $ret
}
proc delay {TimeSec} {
set x 0
after [expr $TimeSec * 1000] {set x 1}
vwait x
}OpenCom IT6800 rmt on IT6800 out on IT6800 cur 1 IT6800 vlt 48 IT6800 get CloseCom
Of course, the program is not final but gives a general idea.
Ilya Ginzburg, RAD Data Communications Ltd. <http://www.rad.com >
CJL suggests that the checksum code could be simplified to the following:
set cs 0
foreach byte $st {
set cs [expr { ($cs + $byte) % 0x100 }]
}
lappend st [format %02x $cs]The ever useful foreach replaces the for/lindex combo. Staying in the integer realm until the last moment avoids lots of string->int->string->int converstions in the original.