# 17tf 17 Tesla magnet of ted forgan & co.
namespace eval 17tf {
}

proc stdConfig::17tf {} {
  variable name
  
  if {[controller std "\n" 10 "\n"]} {
    controllerDesc "17tf controller"
    prop write 17tf::write
  }

  pollperiod 5 5
  obj 17tf wr -drive
  prop read 17tf::read
  prop write 17tf::writemf
  prop checklimits 17tf::checklimits
  prop halt 17tf::halt
  prop status idle
  prop label "set field"
  
  kids "17tf parameters" {

#    node setfield out
#    prop newline 1
    node target upd

    node output upd
    node voltage upd
    node heater upd

    node setrate out
    prop newline 1
    node ramprate upd

    node abort out
    prop newline 1
    prop enum 1
    default 0
    prop write 17tf::abort

    node setunits out
    prop label setunits
    prop enum A/s,T/min,T/hour
    prop lineend 0
    node units upd

    node persistent upd
    node psustatus -text upd
    prop newline 1

    node setpause -text out
    prop label setpause
    prop enum ON=ON,OFF=OFF
    prop lineend 0
    node pausestatus -text upd

    node ignoretbl -text out
    prop label ignoretbl
    prop enum ON=ON,OFF=OFF
    prop lineend 0
    node tblstatus -text upd
    node ready -text upd

    node setpersmode -text out
    prop write 17tf::writepersmode
    prop label setpersmode
    prop enum ON=ON,OFF=OFF
    prop lineend 0
    default ""
    node persmode -text upd

    node persistmode -text upd

    node sensA upd
    node sensB upd

    node set1 out
    prop newline 1
    node setpoint1 upd

    node set2 out
    prop newline 1
    node setpoint2 upd

    node setpid -text out
    prop newline 1
    prop width 40
    default ""
    node L1pid -text upd
    node L2pid -text upd

    node L1power upd
    node L2power upd

    node setrange&mout -text out
    prop newline 1
    default ""
    node L1range upd
    prop newline 1
    node L2range upd
    node L1mout upd
    node L2mout upd

    node setctrl -text out
    prop newline 1
    default ""
    node L1ctrl -text upd
    prop newline 1
    node L2ctrl -text upd

    node setzon -text out
    prop label setzon
    prop enum ON=ON,OFF=OFF
    prop lineend 0
    node zone -text upd

    node tcstatus -text upd
    prop newline 1

    node setposition out
    prop newline 1
    node nv upd

    node setpressure out
    prop newline 1

    node pressure -text upd
    node valvestatus -text upd

    node helevel upd
    node nlevel upd

    node sethefrequency out
    prop label sethefrequency
    prop enum slow,fast,off
    prop lineend 0
    node hefrequency upd

    node attoangle upd

    node attamp upd

    node attfreq upd

  }
  return "17tf forgan and co cryomagnet"
}

proc 17tf::copy_update {to args} {
  set val ""
  foreach from $args {
    if {[string length $from] == 1} {
      append val $from
    } else {
      append val [hvali [sct]/$from]
    }
  }
  hupdate [sct]/$to $val
}

proc 17tf::read {} {
#in getstatus, the value of dummy1 is missing, read it separately
  sct send "dummy1"
  return 17tf::update1
}

proc 17tf::update1 {} {
  hupdate [sct]/persmode [lindex [split [sct result] :] 2]
  copy_update setpersmode persmode

  sct send "getstatus"
  return 17tf::update
}

proc 17tf::update {} {
  set res [sct result]
  if {[string range $res 0 12] ne "getstatus:OK:"} {
    error [string range $res 0 13]
  }
  set res [string range $res 13 end]
  set list [split $res \;]
  foreach par $list {
    if {$par ne ""} {
      set nam [lindex $par 0]
      set val [join [lrange $par 1 end]]
      if {[scan $val "%fT,%fA" fld amp] == 2} {
        set val $fld
      }
#    clientput "|$nam|$val|"
      hupdate [sct]/$nam $val
    }
  }

  set swheater [hvali [sct]/heater]
  if {$swheater == 0} {
    set field [hvali [sct]/output]
  } elseif {$swheater == 1} {
    set field 0
  } else {
    set field [hvali [sct]/persistent]
  }
  if {[sct status] eq "run"} {
#   we are driving, check for finish
    if {abs($field - [sct target]) < 0.001} {
      sct status idle
    } elseif {[hvali [sct]/ready] eq "ON"} {
#     ready might be ON for a short time after setfield?
      if {[sct try] == 0} {
        sct try 1
      } else {
        sct status idle
      }
    } else {
      sct try 1
    }
  }
  sct update $field

#buggy:  copy_update ignoretbl tblstatus
  copy_update setpause pausestatus
  copy_update setrate ramprate
  copy_update setunits units
  copy_update ignoretbl tblstatus

  copy_update set1 setpoint1
  copy_update set2 setpoint2
  copy_update setzon zone
#  copy_update setposition nv
#  hupdate [sct]/setpressure [lindex [split [hvali [sct]/pressure] ,]] 0]
#  copy_update setpressure pressure
  copy_update sethefrequency hefrequency

  copy_update setpid L1pid \; L2Pid
  copy_update setrange&mout L1range , L1mout \; L2range , L2mout
  copy_update setctrl L1ctrl \; L2ctrl
  
  hupdate [sct]/abort 0

  return idle
}

proc 17tf::writemf {} {
  if {[silent 0 sct writestatus] eq "start"} {
    # initiated by a run/drive command
    sct status run
  }
  sct try 0
  sct abortim [clock seconds]
  sct send "ready"
  return 17tf::writemf2
}

proc 17tf::writemf2 {} {
  if {[sct result] ne "ready:OK:ON"} {
    if {[clock seconds] >= [sct abortim]} {
      set try [sct try]
      incr try
      if {$try > 12} {
        sct print "can not abort running field - too many tries"
        return idle
      }
      sct try $try
      # send abort command every 5 seconds
      sct abortim [expr [clock seconds] + 5]
      sct send "abort"
      return 17tf::writemf3
    }
    # ask ready flag continuously during 5 seconds
    sct send "ready"
    return 17tf::writemf2
  }
  sct try 0
  sct print "run [sct objectName] to [sct target]"
  sct send "setfield [sct target]"
  return 17tf::complete
}

proc 17tf::writemf3 {} {
  sct send "ready"
  return 17tf::writemf2
}

proc 17tf::checklimits {} {
  if {abs([sct target]) > 17} {
    error "illegal target value"
  }
}

proc 17tf::halt {} {
  sct send abort
  sct print "abort running [sct objectName]"
  sct status error
  return 17tf::haltcomplete
}

proc 17tf::haltcomplete {} {
  return idle
}

proc 17tf::write {} {
  set name [lindex [split [sct] /] end]
  sct send "$name [sct target]"
  sct update [sct target]
  return 17tf::complete
}

proc 17tf::writepersmode {} {
  sct send "dummy2 [sct target]"
  sct update [sct target]
  return 17tf::complete
}

proc 17tf::complete {} {
  set res [split [sct result] ":"]
  if {[lindex $res 0] ne [lindex [split [sct send]] 0] && [lindex $res 1] ne "OK"} {
    error "bad return value: [sct result]"
  }
  return idle
}

proc 17tf::abort {} {
  sct send abort
  sct update 1
  return stdSct::complete
}

