File AnalogInput.cpp
File List > AnalogInput > AnalogInput.cpp
Go to the documentation of this file
#ifdef ARDUINO_ARCH_STM32
#include "AnalogInput.h"
#include <CANProtocol.h> // sendBatched, canIdEvt, ControlPacket
#include <STM32Board.h>
namespace OpenSkyhawk {
AnalogInput::AnalogInput(uint16_t controlId, PinRef pin, bool reverse,
uint16_t minRaw, uint16_t maxRaw,
uint16_t hysteresis, uint8_t ewmaShift)
: _controlId(controlId),
_pin(pin),
_reverse(reverse),
_minRaw(minRaw),
_maxRaw(maxRaw),
_hysteresis(hysteresis),
_ewmaShift(ewmaShift > MAX_EWMA_SHIFT ? MAX_EWMA_SHIFT : ewmaShift),
_acc(0),
_smoothed(0),
_lastSent(0),
_lastReadMs(0),
_initialized(false) {}
void AnalogInput::configure() {
_pin.configureAsInput();
}
uint16_t AnalogInput::readScaled() {
uint16_t raw =
#ifdef ANALOGINPUT_TEST
_testRawSet ? _testRaw :
#endif
_pin.readAnalog();
if (raw < _minRaw) raw = _minRaw;
else if (raw > _maxRaw) raw = _maxRaw;
// (raw - minRaw) ≤ 65535, × 65535 ≤ 4.29e9 → fits uint32; no Arduino map() overflow.
uint32_t span = (uint32_t)_maxRaw - _minRaw;
uint16_t scaled = span ? (uint16_t)((uint32_t)(raw - _minRaw) * 65535u / span) : 0;
return _reverse ? (uint16_t)(65535u - scaled) : scaled;
}
bool AnalogInput::shouldEmit(uint16_t v) const {
// Ports DcsBios PotentiometerEWMA: emit on > hysteresis movement, or at a rail moving into it.
return (_lastSent > v && (uint16_t)(_lastSent - v) > _hysteresis)
|| (v > _lastSent && (uint16_t)(v - _lastSent) > _hysteresis)
|| (v > (uint16_t)(65535u - _hysteresis) && v > _lastSent)
|| (v < _hysteresis && v < _lastSent);
}
void AnalogInput::emit(uint16_t v, bool init) {
_lastSent = v;
CANProtocol::sendBatched(canIdEvt(NODE_ID), ControlPacket{_controlId, v});
#ifdef ANALOGINPUT_TEST
_emitCount++;
#endif
if (STM32Board::isDebug()) {
auto& d = STM32Board::diagSerial();
d.print(F("[ANA] 0x")); d.print(_controlId, HEX);
d.print(F(": ")); d.print(v);
if (init) d.print(F(" (init)"));
d.println();
}
}
void AnalogInput::sample() {
uint16_t scaled = readScaled();
_acc += (int32_t)scaled - (_acc >> _ewmaShift); // integer EWMA: α = 1/2^ewmaShift
_smoothed = (uint16_t)(_acc >> _ewmaShift);
if (shouldEmit(_smoothed)) emit(_smoothed);
}
void AnalogInput::forceReport() {
uint16_t scaled = readScaled();
_acc = (int32_t)scaled << _ewmaShift; // seed EWMA so smoothed == the current reading
_smoothed = scaled;
_lastReadMs = millis();
_initialized = true;
emit(scaled, true); // baseline, unconditional
}
void AnalogInput::poll() {
if (!_initialized) return;
uint32_t now = millis();
if (now - _lastReadMs < POLL_MS) return; // throttle ADC reads
_lastReadMs = now;
sample();
}
} // namespace OpenSkyhawk
#endif // ARDUINO_ARCH_STM32