From 960be9cd236d42f553b02b10f551a56c9e559ed7 Mon Sep 17 00:00:00 2001 From: Serge Bazanski Date: Sat, 28 Sep 2024 10:17:05 +0200 Subject: [PATCH] succd: rewrite processing loop --- succbone/succd/http.go | 5 +- succbone/succd/process.go | 96 +++++++++++--------------------- succbone/succd/process_blocks.go | 15 ++++- 3 files changed, 50 insertions(+), 66 deletions(-) diff --git a/succbone/succd/http.go b/succbone/succd/http.go index 0d1ce02..61df8a8 100644 --- a/succbone/succd/http.go +++ b/succbone/succd/http.go @@ -84,7 +84,8 @@ type apiData struct { // not being served via websockets). func (s *webServer) apiData(skipSystem bool) *apiData { state := s.d.snapshot() - volts, mbar := state.pirani() + volts := state.piraniVolts100.avg + mbar := state.piraniMbar100.mbar rough, high := state.vacuumStatus() var hostname, load string @@ -164,7 +165,7 @@ func (s *webServer) viewMetrics(w http.ResponseWriter, r *http.Request) { // library. // TODO(q3k): serve the rest of the data model 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, "# TYPE sem_pressure_mbar gauge\n") fmt.Fprintf(w, "sem_pressure_mbar %f\n", mbar) diff --git a/succbone/succd/process.go b/succbone/succd/process.go index 3f23af0..550792b 100644 --- a/succbone/succd/process.go +++ b/succbone/succd/process.go @@ -4,7 +4,6 @@ import ( "context" "errors" "fmt" - "math" "sync" "time" @@ -42,7 +41,9 @@ type daemonState struct { } piraniVolts100 ringbufferInput + piraniMbar100 pfeifferVoltsToMbar piraniVolts3 ringbufferInput + piraniMbar3 pfeifferVoltsToMbar rpOn bool dpOn bool @@ -53,44 +54,6 @@ type daemonState struct { 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) { rough = !d.aboveRough.output high = !d.aboveHigh.output @@ -129,51 +92,58 @@ func (d *daemon) processOnce(_ context.Context) error { // Process pirani ringbuffers. d.piraniVolts3.process(v) + d.piraniMbar3.process(d.piraniVolts3.avg) d.piraniVolts100.process(v) + d.piraniMbar100.process(d.piraniVolts100.avg) d.pumpdown.process() d.vent.process() - _, mbar := d.daemonState.pirani() - d.aboveRough.process(float64(mbar)) - d.aboveHigh.process(float64(mbar)) - - // Check if the pirani gauge is disconnected. Note: this will assume the - // pirani gauge is connected for the first couple of processing runs as - // samples are still being captured. - if d.piraniDetection() == piraniDetectionDisconnected { - // 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)) + // Run safety checks based on small ringbuffer. + if d.piraniVolts3.saturated() { + mbar := d.piraniMbar3.mbar + if !d.safety.failsafe && mbar < 4e-6 { + // 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") } } - } + 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 { + if !d.safety.highPressure && mbar >= 1e-1 { d.safety.highPressure = true 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 { + if d.safety.highPressure && mbar < (1e-1)-(1e-2) { d.safety.highPressure = false 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 { d.aboveRough.output = true d.aboveHigh.output = true d.dpOn = false } - if d.safety.highPressure { d.dpOn = false } diff --git a/succbone/succd/process_blocks.go b/succbone/succd/process_blocks.go index 39d7886..0b37193 100644 --- a/succbone/succd/process_blocks.go +++ b/succbone/succd/process_blocks.go @@ -1,6 +1,9 @@ package main -import "time" +import ( + "math" + "time" +) // momentaryOutput is an output that can be triggered for 500ms. type momentaryOutput struct { @@ -73,3 +76,13 @@ func (r *ringbufferInput) process(input float32) { func (r *ringbufferInput) saturated() bool { 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) +}