Updated 2012-01-14 19:28:54 by RLE

Jorge Moreno - March 31 2006

I needed to monitor equipment down times in a central supervision station, we have a panel with some light indicators, a PC with a National Instruments Digital Input/Ouput Card (called DIO).

So I integrated code from Task Timer,Based numbers,dllcaller and get this script.

It makes use of dll10 [1] to call the dll functions that control the IO hardware
 set dioPresent 0 
 set lstOfTesters {.icthp4\
                    .icthp5\
                    .icthp7\
                    .icthp10\
                    .icthp14\
                    .icthp18\
                    .icthp22\
                    .icthp24\
                    .icthp26\
                    .icthp27\
                    .icthp28\
                    .icthp29\
                    .icthp30\
                    .icthp32\
                    .icthp33\
                   .icthp35\
                   .icthp36\
                   .future\
                         } 
 
 console show
 set ctr 0  
 
 if {$dioPresent} {
 load dll10
 #status = DIG_Prt_Config (deviceNumber, port, mode, dir)
 set i [::dll::call nidaq32.dll DIG_Prt_Config i {i 1} {i 0} {i 0} {i 1}]
 set i [::dll::call nidaq32.dll DIG_Prt_Config i {i 1} {i 1} {i 0} {i 1}]
 set i [::dll::call nidaq32.dll DIG_Prt_Config i {i 1} {i 2} {i 0} {i 1}]
 }
  
 proc base {base number} {
    set negative [regexp ^-(.+) $number -> number] ;# (1)
    set digits {0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N
        O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p
        q r s t u v w x y z}
    set res {}
    while {$number} {
        set digit [expr {$number % $base}]
        set res [lindex $digits $digit]$res
        set number [expr {$number / $base}]
    }
    if $negative {set res -$res}
    set res
 }
 
 proc getPortAndBit {focoNr} {
  #La asignacion consecutiva de puertos de la dio, se comporta como numeros octales, shifted by one.
  return [format "%02s" [base 8 [expr {$focoNr - 1}]]]
 }
 
 proc every {ms body} {
    eval $body
    after $ms [list every $ms $body]
 }
 
 proc timeElapsed {sec} {
    set hours [expr {$sec / 3600}]
    set mins [expr {($sec / 60) % 60}]
    return [format "%02d:%02d" $hours $mins]
 }
 
  proc fmtTime {sec} {
    return [clock format $sec -format %H:%M]
 }
 
 
 # unfmtTime: Take H:M and return decimal hours
 proc unfmtTime {s} {
    set t [split $s ":"]
    set hr [string trimleft [lindex $t 0] "0"]
    if {$hr == ""} {set hr 0}
    set min [string trimleft [lindex $t 1] "0"]
    if {$min == ""} {set min 0}
    set hr [expr {0.01 * round(100 * ($hr + (1.0 * $min)/60))}]
 
    return [format "%.2f" $hr]
 }
 
 ######################################################
 ##
 ## Timer procs
 ##
 ######################################################
 
 proc toggleTimer {win} {
 global timer dioPresent
    if {$timer($win-state)} {
        $win.top.buttons.t config -relief flat
        $win.top.buttons.t config -background green
        set timer($win-state) 0
        set timer($win-inicio) "--/-- --:--"
           resetTimer $win
        #DIG_Out_Line $cardno $port $line $value
        if {$dioPresent} {
            set i [::dll::call nidaq32.dll DIG_Out_Line i {i 1} "i $timer($win-port)" "i $timer($win-bit)" {i 0}]
        }
    } else {
        $win.top.buttons.t config -relief sunken
        $win.top.buttons.t config -background red
        if {$timer($win-reset)} {
            set timer($win-reset) 0
        }
        set timer($win-init) [clock sec]
        set timer($win-state) 1
        if {$dioPresent} {
            set i [::dll::call nidaq32.dll DIG_Out_Line i {i 1} "i $timer($win-port)" "i $timer($win-bit)" {i 1}]
        }
        updateTimer
    }
 }
 
 proc resetTimer {win} {
 global timer    
    set timer($win-reset) 1
    set timer($win-elapsed) "00:00"
    set timer($win-init) [clock sec]
    set timer($win-prev) 0
 }
 
 proc updateTimer {} {
 global timer
    set lastW ""
    foreach win [array names timer] {
        set dashIx [string first - $win]
        set win [string range $win 0 [incr dashIx -1]]
        if {$lastW != $win} {
            set lastW $win
            if {$timer($win-state)} {
                set elapsed_sec [expr {[clock sec] - $timer($win-init)}]
                set timer($win-elapsed) [timeElapsed $elapsed_sec]
                set timer($win-inicio) [clock format $timer($win-init) -format "%m/%d %k:%M"]
            }
        }
    }
 }
 
 
 proc timer_create {win title} {
 global timer ctr
 incr ctr
 # Are we timing, or not?
 set timer($win-state) 0
 # Has the timer been reset?
 set timer($win-reset) 1
 # Store previous time elapsed
 set timer($win-prev) 0
 set timer($win-elapsed) "00:00"
 set timer($win-inicio) "--/-- --:--"
 set timer($win-port) [string range [getPortAndBit $ctr] 0 0]
 set timer($win-bit) [string range [getPortAndBit $ctr] 1 1]
  
 frame $win -class Radiobox
 ## -- Top frame
 frame $win.top
 pack  $win.top -side top
 label $win.top.l -textvar timer($win-inicio) -font {Tahoma 10}
 pack  $win.top.l -side left -padx 6
 
 # Buttons
 frame  $win.top.buttons
 pack   $win.top.buttons -side right -padx 6
 button $win.top.buttons.t -text $title -width 16 -background green
 pack   $win.top.buttons.t -side left
 
 ## -- Bottom frame
 frame $win.bottom
 pack  $win.bottom -side bottom
 label $win.bottom.l -textvar timer($win-elapsed) -font {Tahoma 20}
 pack $win.bottom.l
 $win.top.buttons.t config -command "toggleTimer $win"
 return $win
 }
 
 every [expr 1000 * 60] updateTimer
 foreach {uno dos} $lstOfTesters {
  timer_create $uno $uno
  timer_create $dos $dos
  grid $uno $dos
 }