# temperature reading out commented (search for: tt) 6.5.13

#----- Keithley electrometer

proc kthLayout args {
  Group kth "Keithley 6517B"
}

proc kthMake {host {interval 1}} {
  kth_make kth $host $interval
  Layout kth
  catch {
    kth time0 0.5
    kth time 7
    kth rate 33
    kth sigma 1
  }
  obj_list makeitem kth Keithley6517B
  desc_env makeitem kth Keithley6517B
  hsetprop /sics/kth objectPath /kth
}

proc kthGroup {} {
  showStatus kth
  Input Volt "kth volt"
  CheckBox "Voltage Output" "kth output"
  Newline
  Input "kth Current Range A" "kth crange"
  CheckBox "Autorange" "kth autorange"
  Newline
  Input "Time before Step" "kth time0"
  Input "Time after Step" "kth time"
  Input "Single Measurement Command" "kth measure"
  Newline
  Input "Datafile Path" "kth file" 32
  Input "Ramp Step" "kth rampstep"
  Input "Ramp to Volt" "kth rampto"
}

# -- send command
 
#write action
proc kth_start_send {} {
  set cmd [sct target]
  if {[string first ? $cmd] <= 0} {
    set pos [string first " " $cmd]
    if {$pos > 0} {
      incr pos -1
      set qcmd [string range $cmd 0 $pos]
      sct send "$cmd;$qcmd?"
      return kth_complete_send
    }
  }
  sct send $cmd
  return kth_complete_send
}

#write action, direct   
proc kth_complete_send {} {
  sct print "response = [sct result]" 
  sct update "[sct target]"
  return idle
}  

#config script
proc kth_make_send {path controller} {
  hfactory $path/send plain user text
  $controller write $path/send
  hsetprop $path/send write kth_start_send
  hsetprop $path/send visible false
}

#general error script
proc kth_error_script {} {
  set s [split [sct result] :]
  if {[string equal ASCERR [lindex $s 0]]} {
    set s [lreplace $s 0 0]
  }
  set s [join $s :]
  [sct controllerName] poll [sct tasksPath] 1 start start
  error $s
}

#start action
proc kth_start {} {
  sct send ":FORM:ELEM READ,TST;*IDN?"
  return kth_start_idn
}

#start action, direct
proc kth_start_idn {} {
  set idn [sct result]
  if {! [string equal -length 8 KEITHLEY $idn]} {
    sct send "*IDN?"
    return kth_start_idn
  }
  sct idn $idn
  sct print "connected to $idn"
  return unpoll
}

#read action
proc kth_read {cmd} {
  sct send $cmd
  return update
}

#read action, update state
proc kth_update {{idx 0}} {
  set r [lindex [split [sct result] ,] $idx]
  sct update $r
  return idle
}

#read action, update state
proc kth_update_pico {} {
  set r [lindex [split [sct result] ,] 0]
  sct update [expr $r * 1.0e12]
  return idle
}

#config script
proc kth_rdonly {name queryCmd {skip 0} {interval 5}} {
  global kth

  if {[string equal "" $name]} {
    set node $kth(path)
  } else {
    set node $kth(path)/name
    hfactory $node plain internal float
  }
  logsetup $node
  $kth(controller) poll $node $interval
  hsetprop $node read kth_read $queryCmd
  hsetprop $node update kth_update $skip
}

#write action
proc kth_write {queryCmd} {
  set pos [string first ? $queryCmd]
  if {$pos < 1} {
    error "kth: queryCmd has no question mark"
  }
  set setcmd [string replace [string trim $queryCmd] $pos $pos " "]
  sct send "$setcmd[sct target];$queryCmd"
  return complete
}

#config script
proc kth_combi {name access queryCmd {idx 0}} {
  global kth

  set node $kth(path)/$name
  hfactory $node plain $access float
  logsetup $node
  $kth(controller) write $node
  hsetprop $node write kth_write $queryCmd
  hsetprop $node complete kth_update $idx
  $kth(controller) poll $node 10 slow
  hsetprop $node read kth_read $queryCmd
  hsetprop $node update kth_update $idx
}

#write action
proc kth_measure {} {
  set o [sct objectPath]
  set rate [hvali $o/rate]
  set p0 [expr int([hvali $o/time0] * $rate + 1)]
  set p1 [expr int([hvali $o/time] * $rate + 1)]
  if {$p0 + $p1 >= 200} {
    sct nbg [expr ($p0 + $p1)/200]
    set p1 [expr 200 - $p0]
  } else {
    sct nbg 0
  }
  sct firstrun 1
  sct p1 $p1
  sct p0 $p0
  set step [sct target]
  set ovolt [hvali $o/volt]
  sct ovolt $ovolt
  set volt [expr $ovolt + $step]
  sct volt $volt
  sct send "[string repeat ":data?;" $p0]:source:volt $volt[string repeat ";:data?" $p1]"
#  sct send "[string repeat ":read?;" $p0]:source:volt $volt[string repeat ";:read?" $p1]"
  sct print "measure $ovolt => $volt"
  return kth_complete_measure
}

proc kth_filename {path} {
  set num 1
  catch {
    set fil [open $path/datanumber.txt r]
    gets $fil num
    close $fil
  }
  incr num
  set fil [open $path/datanumber.tmp w]
  puts $fil $num
  puts $fil "^   this is the highest data file number used"
  puts $fil "delete or modify this file if you want to overwrite data files"
  close $fil
  file rename -force $path/datanumber.tmp $path/datanumber.txt
  return $path/data[format "%.4d" $num].txt
}

#complete action
proc kth_complete_measure {} {
  global kth

  set o [sct objectPath]
  set rl [split [sct result] ";"]
  set p0 [sct p0]
  set p1 [sct p1]
  set Temperature [result tt ts]

  if {[sct firstrun]} {
    set dl [split [lindex $rl $p0] ,]
    set kth(t0) [lindex $dl 1]
    set kth(filename) [kth_filename [hvali $o/file]]
    set fil [open $kth(filename) w]
    puts $fil "#time	value	dummySigma	voltage=[sct volt]	T= [expr $Temperature] "
#    puts $fil "#time	value	dummySigma	voltage=[sct volt]"
    sct firstrun 0
  } else {
    set fil [open $kth(filename) a]
  }
  set last 0
  foreach d $rl {
    set dl [split $d ,]
    set t [lindex $dl 1]
    set y [expr [lindex $dl 0] * 1.0e12]
    if {$t != $last && abs($y) < 1.0e12} {
      set last $t
      puts $fil "[expr $t - $kth(t0)] $y [hvali $o/sigma] [sct volt] $Temperature "
    }
  }
  close $fil
  if {[sct nbg] <= 0} {
    sct print "$kth(filename) written"
    hupdate $o/volt [sct volt]
    sct update [sct target]
    return idle
  }
  sct nbg [expr [sct nbg] - 1]
  sct send "[string repeat ":data?;" 200]:data?"
  sct print "$kth(filename) - measure background"
  return kth_complete_measure
}

proc kth_rampto {} {
  set o [sct objectPath]
  set volt [hvali $o/volt]
  set diff [expr [sct target] - $volt]
  if {$diff == 0} {
    sct print "we are already at [sct target] volt"
    return unpoll
  }
  set rampstep [expr abs([hvali $o/rampstep])]
  if {$diff < 0} {
    set rampstep -$rampstep
  }
  [sct controllerName] poll [sct] 1 progress progress
  sct progress kth_progress
  sct print "start ramp to [sct target]"
  sct update [sct target]
  hset $o/measure $rampstep
  return idle
}

proc kth_progress {} {
  set o [sct objectPath]
  set volt [hvali $o/volt]
  set diff [expr [sct target] - $volt]
  if {abs($diff) < 0.001} {
    return unpoll
  }
  if {$volt == [hgetpropval $o/measure volt]} {
    set rampstep [expr abs([hvali $o/rampstep])]
    if {$diff > 0} {
      if {$volt + $rampstep >= [sct target]} {
        set rampstep [expr [sct target] - $volt]
      }
    } else {
      set rampstep -$rampstep
      if {$volt + $rampstep <= [sct target]} {
        set rampstep [expr [sct target] - $volt]
      }
    }
    hset $o/measure $rampstep
  }
  return idle
}

proc kth_make {objectName host {interval 1}} {
  global kth

clientput "kth_make $objectName $host $interval"
  set controllerName ctrl_$objectName
  makesctcontroller $controllerName std $host "\r" 20
  set path /$objectName
  set kth(path) $path
  set kth(controller) $controllerName

  hfactory $path plain user float
  dynsctdriveobj $objectName $path K6517B $controllerName

  hfactory $path/controller link $controllerName

  hfactory $path/tasks plain user none
  hsetprop $path/tasks start kth_start
  hsetprop $path/tasks visible false

  hsetprop $path/controller idn empty
  hsetprop $path/controller visible false
  hsetprop $path/controller tasksPath $path/tasks
  hsetprop $path/controller objectPath $path
  hsetprop $path/controller objectName $objectName
  hsetprop $path/controller state idle
  hsetprop $path/controller commerror kth_error_script

  kth_make_send $path $controllerName
  $controllerName queue $kth(path)/tasks start start

  hfactory $kth(path)/time0 plain user float
  logsetup $kth(path)/time0

  hfactory $kth(path)/time plain user float
  logsetup $kth(path)/time

  hfactory $kth(path)/rate plain user float
  logsetup $kth(path)/rate

  hfactory $kth(path)/file plain user text
  logsetup $kth(path)/file

  hupdate $kth(path)/file test

  hfactory $kth(path)/sigma plain user float
  logsetup $kth(path)/sigma

  hfactory $kth(path)/status plain user text
  hupdate $kth(path)/status ""

  hfactory $kth(path)/sugar plain user text
  hupdate $kth(path)/sugar ""

  set node $kth(path)/measure
  hfactory $node plain user float
  $kth(controller) write $node
  hsetprop $node write kth_measure

  set node $kth(path)/rampto
  hfactory $node plain user text
  $kth(controller) write $node
  hsetprop $node write kth_rampto

  hfactory $kth(path)/rampstep plain user float
  logsetup $kth(path)/rampstep

  kth_rdonly "" ":SENS1:DATA?" 0 $interval
  hsetprop $kth(path) update kth_update_pico
  kth_combi volt user ":SOURCE:VOLT?" 0
  kth_combi output user ":OUTP1:STAT?" 0
  kth_combi crange user ":SENS:CURR:DC:RANG?" 0
  kth_combi autorange user ":SENS:CURR:DC:RANG:AUTO?" 0

  if {[string first [result vars] "kth.volt"] <= 0} {
    vars = "[result vars] kth/pA/Kth/1 kth.volt/V/Volt/1"
  }

  hset $kth(path)/time0 0.5
  hset $kth(path)/time 7
  hset $kth(path)/rate 33
  hset $kth(path)/sigma 1
  hupdate $kth(path)/rampstep 1
  hupdate $kth(path)/rampto 0

}
