#
# Automatic N2 refill
#
# watching state (2):
#   if lower sensor falls below startvalue for more than startdelay seconds,
#   start fill, go to fillstart state (3)
# fillstart state (3):
#   wait fillmini seconds, then go to filling state
# filling state (4):
#   if upper sensor goes beyond fillvalue for more than filldelay seconds,
#   stip fill, go to quiet state (1)
# quiet state (1):
#   wait stopmini seconds, then go to watching state (2)

proc makeN2fill {} {
  makeobject n2fillPar array logged
  n2fillPar makeitem state 0
  n2fillPar makeitem lower "tt tm"
  n2fillPar makeitem upper "tt ts"
  n2fillPar makeitem startvalue 100
  n2fillPar makeitem stopvalue 100
  n2fillPar makeitem lasttime 0
  n2fillPar makeitem lastcron 0
  n2fillPar makeitem startdelay 10
  n2fillPar makeitem stopdelay 5
  n2fillPar makeitem fillmini 10
  n2fillPar makeitem stopmini 60
  n2fillPar makeitem instance 0
  n2fillPar makeitem errcnt 0
  obj_list makeitem n2fillPar "LN2 refill parameters"
  Layout n2fill
}

proc n2fillLayout args {
  Group n2fill "LN2 refill"
}

proc n2fillGroup args {
  showStatus n2fill
  RadioGroup n2fill
  Label "LN2 refill"
  NoNewline
  CheckBox active "n2fill on"
  if {[result n2fill on]} {
    NoNewline
    CheckBox fill "n2fill fill"
  }
  NoNewline
  Label "state: [result n2fill]"
  Newline
  Tip "upper sensor parameter name"
  Input "upper sensor" "n2fillPar upper"
  Tip "lower sensor parameter name"
  Input "lower sensor" "n2fillPar lower"
  Newline
  Tip "switch-off value on upper sensor"
  Input "stop value" "n2fillPar stopvalue"
  Tip "switch-on value on lower sensor"
  Input "start value" "n2fillPar startvalue"
  Newline
  Input "start delay" "n2fillPar startdelay"
  Input "stop delay" "n2fillPar stopdelay"
  Newline
  Tip "minimum switch-on time"
  Input "minimum fill time" "n2fillPar fillmini"
  Tip "minimum switch-off time"
  Input "minimum stop time" "n2fillPar stopmini"
  Newline
}

proc n2state {state} {
  n2fillPar lasttime [clock seconds]
  if {$state > 2} {
    clientput "valve ON"
    tt send relay 2:2,1
  } else {
    clientput "valve OFF"
    tt send relay 2:2,0
  }
  n2fillPar state $state
}

proc n2fill {{action none} {value none}} {
  set now [clock seconds]
  set lasttime [result n2fillPar lasttime]
  set uval [result eval [result n2fillPar upper]]
  set lval [result eval [result n2fillPar lower]]
  set state [result n2fillPar state]
  set errcnt [result n2fillPar errcnt]
  switch -- $action {
    none {
      switch -- $state {
        0 { return "n2fill = off (0)" }
        1 { return "n2fill = quiet (1)" }
        2 { return "n2fill = watching (2)" }
        3 { return "n2fill = fillstart (3)" }
        4 { return "n2fill = filling (4)" }
      }
    }
    cron {
      n2fillPar lastcron $now
      if {$value != [result n2fillPar instance]} {
        n2state 0
        error "n2fill instance $value stopped"
      }
      if {$uval < 420 && $uval > 65 && $lval < 420 && $lval > 65} {
        n2fillPar errcnt 0
      } else {
        incr errcnt
        if {$errcnt >= 5} {
          n2state 0
          error "illegal upper ($uval) or lower ($lval) temperature"
        }
        n2fillPar errcnt $errcnt
        return
      }
      switch -- $state {
        3 {
          if {$now > $lasttime + [result n2fillPar fillmini]} {
            n2state 4
          }
        }
        4 {
          if {$uval < [result n2fillPar stopvalue]} {
            if {$now > $lasttime + [result n2fillpar stopdelay]} {
              n2state 1
            }
          } else {
            n2fillpar lasttime $now
          }
        }
        1 {
          if {$now > $lasttime + [result n2fillPar stopmini]} {
            n2state 2
          }
        }
        2 {
          if {$lval > [result n2fillPar startvalue] && $lval < 250} {
            if {$now > $lasttime + [result n2fillpar startdelay]} {
              n2state 3
            }
          } else {
            n2fillpar lasttime $now
          }
        }
        default {
          error "n2fill stopped with state $state"
        }
      }
    }
    on {
      switch -- $value {
        1 {
          set instance [result n2fillPar instance]
          incr instance
          n2fillPar instance $instance
          sicscron 1 n2fill cron $instance
          n2state 2
          return "n2fill.on = 1"
        }
        0 {
          n2state 0
          return "n2fill.on = 0"
        }
        none {
          if {$now > [result n2fillPar lastcron] + 10} {
            return "n2fill.on = 0"
          }
          if {$state > 0} {
            return "n2fill.on = 1"
          } else {
            return "n2fill.on = 0"
          }
        }
      }
    }
    fill {
      switch -- $value {
        1 {
          n2state 4
          return "n2fill.fill = 1"
        }
        0 {
          n2state 2
          return "n2fill.fill = 1"
        }
        none {
          if {$state > 2} {
            return "n2fill.fill = 1"
          } else {
            return "n2fill.fill = 0"
          }
        }
      }
    }
  }
}

publishLazy n2fill spy
