# Andeen Hagerling 2700 capacitance bridge
namespace eval ah2700 {} {
}

proc stdConfig::ah2700 {} {
  controller std sendterminator=\r timeout=15 lineseparator=,

  variable node
  set node $node/tasks
  prop start ah2700::start

  obj AH2700 rd -none
  prop read ah2700::read
  prop do_read_avg 1
  prop period 0
  prop cnt 0

  kids ah2700 {
    node cap upd
    prop fmt %.8f

    node loss upd
    prop fmt %.8f

    node period out
    default 5
    prop check ah2700::change_period
    prop write stdSct::complete

    node freq out
    prop label Frequency
    prop writecmd "FR %g;SI"
    prop complete ah2700::update

    node  V out
    prop label Exitation Voltage
    prop writecmd "V %g;SI"
    prop complete ah2700::update

    node average out -int
    prop label "average setting"
    prop writecmd "AV %d;SH AV"
    prop complete ah2700::update_av
  }
}

proc ah2700::start {} {
  sct send "UN DS"
  return ah2700::start1
}

proc ah2700::start1 {} {
  set prefix [lindex [sct result] 0]
  if {$prefix eq "UN"} { # this was the echo
    sct send "SERIAL ECHO OFF"
    return ah2700::start
  }
  if {$prefix ne "F=" && [sct result] ne "NO DATA FOUND"} {
    error "bad response: [sct result]"
  }
  sct send "*IDN?{4}"
  return ah2700::start2
}

proc ah2700::start2 {} {
  sct result [join [sct result]]
  return stdSct::completeStart
}

proc ah2700::read {} {
  sct send "SI"
  sct sendtime [DoubleTime]
  return ah2700::update
}

proc ah2700::update {} {
  # analyze result: _ is a placeholder for text words
  lassign [string map {"=" "= "} [sct result]] prefix f _ _ c _ _ l un _ v
  if {$prefix eq "SI"} {
    sct send "\r\nSERIAL ECHO OFF\r"
    return stdSct::complete
  }
  if {$prefix eq "F="} {
    hupdate [sct objectPath]/status ""
  } else {
    hupdate [sct objectPath]/status [sct result]
  }
  set period [expr [DoubleTime] - [sct sendtime] + 0.1]
  sct cnt [expr min(20, [sct cnt] + 1)]
  set dif [expr $period - [sct period]]
  sct period [expr [sct period] + $dif / [sct cnt]]
  if {abs([sct period] - [hval [sct]/period]) > 0.1 || [sct cnt] == 10} {
    set period [format {%.1f} [sct period]]
    if {$period != [hval [sct]/period]} {
      hupdate [sct]/period [format {%.1f} $period]
      set_period [sct] $period
      sct do_read_avg 1
    }
  }
  hupdate [sct objectPath]/cap $c
  hupdate [sct objectPath]/freq $f
  hupdate [sct objectPath]/V $v
  if {$un ne "DS"} {
    sct send "UN DS"
    return ah2700::update
  }
  hupdate [sct objectPath]/loss $l
  if {[sct do_read_avg]} {
    sct do_read_avg 0
    sct send "SH AV"
    return ah2700::update_av
  }
  return idle
}

proc ah2700::update_av {} {
  set res [lindex [split [sct result] =] end]
  catch {
    hupdate [sct objectPath]/average $res
  } msg
  hsetprop [sct objectPath] cnt 0
  return idle
}

proc ah2700::set_period {node target} {
  [sct controllerName] poll $node $target
  hupdate $node/period $target
}

proc ah2700::change_period {} {
  set_period [sct objectPath] [sct target]
  return idle
}

