diff --git a/succbone/succd/process.go b/succbone/succd/process.go index b285fab..a62c261 100644 --- a/succbone/succd/process.go +++ b/succbone/succd/process.go @@ -28,71 +28,6 @@ type daemon struct { daemonState } -// momentaryOutput is an output that can be triggered for 500ms. -type momentaryOutput struct { - // output of the block. - output bool - // scheduledOff is when the block should be outputting false again. - scheduledOff time.Time -} - -func (m *momentaryOutput) process() { - m.output = m.scheduledOff.After(time.Now()) -} - -func (m *momentaryOutput) trigger() { - m.scheduledOff = time.Now().Add(time.Millisecond * 500) -} - -// thresholdOutput outputs true if a given value is above a setpoint/threshold. -// It contains debounce logic for processing noisy analog signals. -type thresholdOutput struct { - // output of the block. - output bool - // debounce is when the debouncer should be inactive again. - debounce time.Time - // threshold is the setpoint of the block. - threshold float64 -} - -func (t *thresholdOutput) process(value float64) { - if time.Now().Before(t.debounce) { - return - } - new := value > t.threshold - if new != t.output { - t.output = new - t.debounce = time.Now().Add(time.Second * 5) - } -} - -// ringbufferInput accumulates analog data up to limit samples, and calculates -// an average. -type ringbufferInput struct { - data []float32 - limit uint - avg float32 -} - -func (r *ringbufferInput) process(input float32) { - // TODO(q3k): use actual ringbuffer - // TODO(q3k): optimize average calculation - // TODO(q3k): precalculate value in mbar - r.data = append(r.data, input) - trim := len(r.data) - int(r.limit) - if trim > 0 { - r.data = r.data[trim:] - } - avg := float32(0.0) - for _, v := range r.data { - avg += v - } - if len(r.data) != 0 { - avg /= float32(len(r.data)) - } - r.avg = avg -} - // process runs the pain acquisition and control loop of succd. func (d *daemon) process(ctx context.Context) { ticker := time.NewTicker(time.Millisecond * 100) diff --git a/succbone/succd/process_blocks.go b/succbone/succd/process_blocks.go new file mode 100644 index 0000000..39d7886 --- /dev/null +++ b/succbone/succd/process_blocks.go @@ -0,0 +1,75 @@ +package main + +import "time" + +// momentaryOutput is an output that can be triggered for 500ms. +type momentaryOutput struct { + // output of the block. + output bool + // scheduledOff is when the block should be outputting false again. + scheduledOff time.Time +} + +func (m *momentaryOutput) process() { + m.output = m.scheduledOff.After(time.Now()) +} + +func (m *momentaryOutput) trigger() { + m.scheduledOff = time.Now().Add(time.Millisecond * 500) +} + +// thresholdOutput outputs true if a given value is above a setpoint/threshold. +// It contains debounce logic for processing noisy analog signals. +type thresholdOutput struct { + // output of the block. + output bool + // debounce is when the debouncer should be inactive again. + debounce time.Time + // threshold is the setpoint of the block. + threshold float64 +} + +func (t *thresholdOutput) process(value float64) { + if time.Now().Before(t.debounce) { + return + } + new := value > t.threshold + if new != t.output { + t.output = new + t.debounce = time.Now().Add(time.Second * 5) + } +} + +// ringbufferInput accumulates analog data up to limit samples, and calculates +// an average. +type ringbufferInput struct { + data []float32 + limit uint + // avg is the mean average of the samples in data, or 0.0 if no data is + // present yet. This is the main output of the block. + avg float32 +} + +func (r *ringbufferInput) process(input float32) { + // TODO(q3k): use actual ringbuffer + // TODO(q3k): optimize average calculation + // TODO(q3k): precalculate value in mbar + r.data = append(r.data, input) + trim := len(r.data) - int(r.limit) + if trim > 0 { + r.data = r.data[trim:] + } + avg := float32(0.0) + for _, v := range r.data { + avg += v + } + if len(r.data) != 0 { + avg /= float32(len(r.data)) + } + r.avg = avg +} + +// saturated returns true if the number of samples is at the configured limit. +func (r *ringbufferInput) saturated() bool { + return len(r.data) >= int(r.limit) +} diff --git a/succbone/succd/process_state.go b/succbone/succd/process_state.go index 8ed1c41..c7ab5eb 100644 --- a/succbone/succd/process_state.go +++ b/succbone/succd/process_state.go @@ -50,7 +50,7 @@ func piraniVoltsToMbar(v float32) float32 { // piraniDetection guesses whether the pirani gauge is connected. func (d *daemonState) piraniDetection() piraniDetection { - if len(d.piraniVolts3.data) < int(d.piraniVolts3.limit) { + if !d.piraniVolts3.saturated() { return piraniDetectionUnknown } mbar := piraniVoltsToMbar(d.piraniVolts3.avg)