succd: rewrite processing loop
This commit is contained in:
parent
3d81a1f56c
commit
960be9cd23
|
@ -84,7 +84,8 @@ type apiData struct {
|
||||||
// not being served via websockets).
|
// not being served via websockets).
|
||||||
func (s *webServer) apiData(skipSystem bool) *apiData {
|
func (s *webServer) apiData(skipSystem bool) *apiData {
|
||||||
state := s.d.snapshot()
|
state := s.d.snapshot()
|
||||||
volts, mbar := state.pirani()
|
volts := state.piraniVolts100.avg
|
||||||
|
mbar := state.piraniMbar100.mbar
|
||||||
rough, high := state.vacuumStatus()
|
rough, high := state.vacuumStatus()
|
||||||
|
|
||||||
var hostname, load string
|
var hostname, load string
|
||||||
|
@ -164,7 +165,7 @@ func (s *webServer) viewMetrics(w http.ResponseWriter, r *http.Request) {
|
||||||
// library.
|
// library.
|
||||||
// TODO(q3k): serve the rest of the data model
|
// TODO(q3k): serve the rest of the data model
|
||||||
state := s.d.snapshot()
|
state := s.d.snapshot()
|
||||||
_, mbar := state.pirani()
|
mbar := state.piraniMbar100.mbar
|
||||||
fmt.Fprintf(w, "# HELP sem_pressure_mbar Pressure in the SEM chamber, in millibar\n")
|
fmt.Fprintf(w, "# HELP sem_pressure_mbar Pressure in the SEM chamber, in millibar\n")
|
||||||
fmt.Fprintf(w, "# TYPE sem_pressure_mbar gauge\n")
|
fmt.Fprintf(w, "# TYPE sem_pressure_mbar gauge\n")
|
||||||
fmt.Fprintf(w, "sem_pressure_mbar %f\n", mbar)
|
fmt.Fprintf(w, "sem_pressure_mbar %f\n", mbar)
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -42,7 +41,9 @@ type daemonState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
piraniVolts100 ringbufferInput
|
piraniVolts100 ringbufferInput
|
||||||
|
piraniMbar100 pfeifferVoltsToMbar
|
||||||
piraniVolts3 ringbufferInput
|
piraniVolts3 ringbufferInput
|
||||||
|
piraniMbar3 pfeifferVoltsToMbar
|
||||||
|
|
||||||
rpOn bool
|
rpOn bool
|
||||||
dpOn bool
|
dpOn bool
|
||||||
|
@ -53,44 +54,6 @@ type daemonState struct {
|
||||||
aboveHigh thresholdOutput
|
aboveHigh thresholdOutput
|
||||||
}
|
}
|
||||||
|
|
||||||
type piraniDetection uint
|
|
||||||
|
|
||||||
const (
|
|
||||||
// piraniDetectionUnknown means the system isn't yet sure whether the pirani
|
|
||||||
// gauge is connected.
|
|
||||||
piraniDetectionUnknown piraniDetection = iota
|
|
||||||
// piraniDetectionConnected means the system assumes the pirani gauge is
|
|
||||||
// connected.
|
|
||||||
piraniDetectionConnected = iota
|
|
||||||
// piraniDetectionDisconnected means the system assumes the pirani gauge is
|
|
||||||
// disconnected.
|
|
||||||
piraniDetectionDisconnected = iota
|
|
||||||
)
|
|
||||||
|
|
||||||
func piraniVoltsToMbar(v float32) float32 {
|
|
||||||
// Per Pirani probe docs.
|
|
||||||
bar := math.Pow(10.0, float64(v)-8.5)
|
|
||||||
return float32(bar * 1000.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// piraniDetection guesses whether the pirani gauge is connected.
|
|
||||||
func (d *daemonState) piraniDetection() piraniDetection {
|
|
||||||
if !d.piraniVolts3.saturated() {
|
|
||||||
return piraniDetectionUnknown
|
|
||||||
}
|
|
||||||
mbar := piraniVoltsToMbar(d.piraniVolts3.avg)
|
|
||||||
if mbar < 4e-6 {
|
|
||||||
return piraniDetectionDisconnected
|
|
||||||
}
|
|
||||||
return piraniDetectionConnected
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *daemonState) pirani() (volts float32, mbar float32) {
|
|
||||||
volts = d.piraniVolts100.avg
|
|
||||||
mbar = piraniVoltsToMbar(volts)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (d *daemonState) vacuumStatus() (rough, high bool) {
|
func (d *daemonState) vacuumStatus() (rough, high bool) {
|
||||||
rough = !d.aboveRough.output
|
rough = !d.aboveRough.output
|
||||||
high = !d.aboveHigh.output
|
high = !d.aboveHigh.output
|
||||||
|
@ -129,51 +92,58 @@ func (d *daemon) processOnce(_ context.Context) error {
|
||||||
|
|
||||||
// Process pirani ringbuffers.
|
// Process pirani ringbuffers.
|
||||||
d.piraniVolts3.process(v)
|
d.piraniVolts3.process(v)
|
||||||
|
d.piraniMbar3.process(d.piraniVolts3.avg)
|
||||||
d.piraniVolts100.process(v)
|
d.piraniVolts100.process(v)
|
||||||
|
d.piraniMbar100.process(d.piraniVolts100.avg)
|
||||||
|
|
||||||
d.pumpdown.process()
|
d.pumpdown.process()
|
||||||
d.vent.process()
|
d.vent.process()
|
||||||
|
|
||||||
_, mbar := d.daemonState.pirani()
|
// Run safety checks based on small ringbuffer.
|
||||||
d.aboveRough.process(float64(mbar))
|
if d.piraniVolts3.saturated() {
|
||||||
d.aboveHigh.process(float64(mbar))
|
mbar := d.piraniMbar3.mbar
|
||||||
|
if !d.safety.failsafe && mbar < 4e-6 {
|
||||||
// Check if the pirani gauge is disconnected. Note: this will assume the
|
// Unrealistic result, Pirani probe probably disconnected. Failsafe mode.
|
||||||
// pirani gauge is connected for the first couple of processing runs as
|
if !d.safety.failsafe {
|
||||||
// samples are still being captured.
|
d.safety.failsafe = true
|
||||||
if d.piraniDetection() == piraniDetectionDisconnected {
|
klog.Errorf("Pirani probe seems disconnected; enabling failsafe mode")
|
||||||
// Unrealistic result, Pirani probe probably disconnected. Failsafe mode.
|
|
||||||
if !d.safety.failsafe {
|
|
||||||
d.safety.failsafe = true
|
|
||||||
klog.Errorf("Pirani probe seems disconnected; enabling failsafe mode")
|
|
||||||
}
|
|
||||||
} else if d.piraniDetection() == piraniDetectionConnected {
|
|
||||||
if d.safety.failsafe {
|
|
||||||
if mbar >= 1e2 {
|
|
||||||
d.safety.failsafe = false
|
|
||||||
klog.Infof("Pirani probe value (%s) is plausible again; quitting failsafe mode", formatMbar(mbar))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if d.safety.failsafe && mbar > 1e2 {
|
||||||
|
d.safety.failsafe = false
|
||||||
|
klog.Infof("Pirani probe value (%s) is plausible again; quitting failsafe mode", formatMbar(mbar))
|
||||||
|
}
|
||||||
|
|
||||||
if mbar >= 1e-1 {
|
if !d.safety.highPressure && mbar >= 1e-1 {
|
||||||
if !d.safety.highPressure {
|
|
||||||
d.safety.highPressure = true
|
d.safety.highPressure = true
|
||||||
klog.Warningf("Pressure is too high (%s mbar); enabling diffusion pump lockout", formatMbar(mbar))
|
klog.Warningf("Pressure is too high (%s mbar); enabling diffusion pump lockout", formatMbar(mbar))
|
||||||
}
|
}
|
||||||
} else if mbar < (1e-1)-(1e-2) {
|
if d.safety.highPressure && mbar < (1e-1)-(1e-2) {
|
||||||
if d.safety.highPressure {
|
|
||||||
d.safety.highPressure = false
|
d.safety.highPressure = false
|
||||||
klog.Infof("Pressure is low enough (%s mbar) for diffusion pump operation; quitting diffusion pump lockout", formatMbar(mbar))
|
klog.Infof("Pressure is low enough (%s mbar) for diffusion pump operation; quitting diffusion pump lockout", formatMbar(mbar))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
d.safety.failsafe = true
|
||||||
|
d.safety.highPressure = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Control threhold/feedback values based on main pirani ringbuffer, failing
|
||||||
|
// safe if not enough data is present.
|
||||||
|
if d.piraniVolts100.saturated() {
|
||||||
|
mbar := d.piraniMbar100.mbar
|
||||||
|
d.aboveRough.process(float64(mbar))
|
||||||
|
d.aboveHigh.process(float64(mbar))
|
||||||
|
} else {
|
||||||
|
d.aboveRough.output = true
|
||||||
|
d.aboveHigh.output = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply safety overrides.
|
||||||
if d.safety.failsafe {
|
if d.safety.failsafe {
|
||||||
d.aboveRough.output = true
|
d.aboveRough.output = true
|
||||||
d.aboveHigh.output = true
|
d.aboveHigh.output = true
|
||||||
d.dpOn = false
|
d.dpOn = false
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.safety.highPressure {
|
if d.safety.highPressure {
|
||||||
d.dpOn = false
|
d.dpOn = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import "time"
|
import (
|
||||||
|
"math"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
// momentaryOutput is an output that can be triggered for 500ms.
|
// momentaryOutput is an output that can be triggered for 500ms.
|
||||||
type momentaryOutput struct {
|
type momentaryOutput struct {
|
||||||
|
@ -73,3 +76,13 @@ func (r *ringbufferInput) process(input float32) {
|
||||||
func (r *ringbufferInput) saturated() bool {
|
func (r *ringbufferInput) saturated() bool {
|
||||||
return len(r.data) >= int(r.limit)
|
return len(r.data) >= int(r.limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type pfeifferVoltsToMbar struct {
|
||||||
|
mbar float32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *pfeifferVoltsToMbar) process(volts float32) {
|
||||||
|
// Per Pirani probe docs.
|
||||||
|
bar := math.Pow(10.0, float64(volts)-8.5)
|
||||||
|
p.mbar = float32(bar * 1000.0)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue