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) }