diff --git a/lib/arduino/senseshift/arduino/input/sensor/analog.hpp b/lib/arduino/senseshift/arduino/input/sensor/analog.hpp index dbef7c39..71a9af01 100644 --- a/lib/arduino/senseshift/arduino/input/sensor/analog.hpp +++ b/lib/arduino/senseshift/arduino/input/sensor/analog.hpp @@ -18,29 +18,20 @@ #endif namespace SenseShift::Arduino::Input { - template class AnalogSimpleSensor : public ::SenseShift::Input::IFloatSimpleSensor { - std::uint8_t pin_; + const std::uint8_t pin_; public: + static constexpr float MAX_VALUE = ANALOG_MAX; + explicit AnalogSimpleSensor(const std::uint8_t pin) : pin_(pin) {} void init() override { pinMode(this->pin_, INPUT); }; - [[nodiscard]] auto getValue() -> float override; + [[nodiscard]] inline auto getValue() -> float override + { + const std::uint16_t raw = analogRead(this->pin_); + return static_cast(raw) / ANALOG_MAX; + } }; - - template<> - [[nodiscard]] inline auto AnalogSimpleSensor::getValue() -> float - { - const std::uint16_t raw = analogRead(this->pin_); - return static_cast(raw) / ANALOG_MAX; - } - - template<> - [[nodiscard]] inline auto AnalogSimpleSensor::getValue() -> float - { - const std::uint16_t raw = ANALOG_MAX - analogRead(this->pin_); - return static_cast(raw) / ANALOG_MAX; - } } // namespace SenseShift::Arduino::Input diff --git a/lib/arduino/senseshift/arduino/input/sensor/multiplexer.hpp b/lib/arduino/senseshift/arduino/input/sensor/multiplexer.hpp new file mode 100644 index 00000000..d6b1bb9c --- /dev/null +++ b/lib/arduino/senseshift/arduino/input/sensor/multiplexer.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include +#include +#include +#include + +#include + +#include "senseshift/arduino/input/sensor/analog.hpp" + +#include +#include + +namespace SenseShift::Arduino::Input { + template + class Multiplexer : public IInitializable { + public: + /// \param pins The pins to use for the multiplexer. + explicit Multiplexer(const std::array& pins, const size_t switch_delay_us = 2) : + pins_(pins), switch_delay_us_(switch_delay_us) + { + } + + void init() override + { + for (const auto pin : this->pins_) { + pinMode(pin, OUTPUT); + } + } + + /// Select the channel. + /// \param channel The channel to select. + void selectChannel(const std::uint8_t channel) + { + if (channel >= (1 << N) || this->active_channel_ == channel) { + return; + } + + for (size_t i = 0; i < N; ++i) { + digitalWrite(this->pins_[i], (channel >> i) & 0b0001); + } + + delayMicroseconds(this->switch_delay_us_); + + this->active_channel_ = channel; + } + + private: + const std::array pins_; + std::uint8_t active_channel_ = 0; + const size_t switch_delay_us_; + }; + + using MUX_CD74HC4057Component = Multiplexer<4>; + using MUX_74HC4051Component = Multiplexer<3>; + + template + class MultiplexedSensor : public AnalogSimpleSensor { + public: + /// \param component The CD74HC4057 Component to use. + /// \param pin The SIG pin of the sensor. + /// \param channel The channel to read from. + MultiplexedSensor(Multiplexer* component, const std::uint8_t pin_sig, const std::uint8_t channel) : + component_(component), AnalogSimpleSensor(pin_sig), channel_(channel) + { + assert(channel < (1 << N) && "Channel out of range"); + } + + void init() override + { + this->component_->init(); + AnalogSimpleSensor::init(); + } + + [[nodiscard]] auto getValue() -> float override + { + this->component_->selectChannel(this->channel_); + + return AnalogSimpleSensor::getValue(); + } + + private: + Multiplexer* component_; + const std::uint8_t channel_; + }; +} // namespace SenseShift::Arduino::Input diff --git a/lib/io/senseshift/input/filter.hpp b/lib/io/senseshift/input/filter.hpp index 4fa3bb15..01a4f495 100644 --- a/lib/io/senseshift/input/filter.hpp +++ b/lib/io/senseshift/input/filter.hpp @@ -300,4 +300,10 @@ namespace SenseShift::Input::Filter { private: Container const& lookup_table_; }; + + /// Specialized filter for analog sensors (between 0.0 and 1.0). + class AnalogInvertFilter : public IFilter { + public: + auto filter(ISimpleSensor* /*sensor*/, float value) -> float override { return 1.0F - value; } + }; } // namespace SenseShift::Input::Filter diff --git a/lib/opengloves/senseshift/opengloves/autoconfig.hpp b/lib/opengloves/senseshift/opengloves/autoconfig.hpp index 98ba482d..53229993 100644 --- a/lib/opengloves/senseshift/opengloves/autoconfig.hpp +++ b/lib/opengloves/senseshift/opengloves/autoconfig.hpp @@ -1,8 +1,5 @@ #pragma once -#include -#include -#include #include #include #include @@ -12,6 +9,10 @@ #include #ifdef ARDUINO +#include +#include +#include +#include #include #endif @@ -82,11 +83,13 @@ #define FINGER_PINKY_ENABLED false #endif -#define DEFINE_FINGER(NAME, CURL_PIN, CURL_INVERT, CURL_CALIB) \ - auto* NAME##_sensor = new ::SenseShift::Input::SimpleSensorDecorator( \ - new ::SenseShift::Arduino::Input::AnalogSimpleSensor(CURL_PIN) \ - ); \ - NAME##_sensor->addFilters({ new ::SenseShift::Input::Filter::ExponentialMovingAverageFilter(0.8F) }); \ +#define DEFINE_FINGER(NAME, CURL_PIN, CURL_INVERT, CURL_CALIB) \ + auto* NAME##_sensor = \ + new ::SenseShift::Input::SimpleSensorDecorator(new ::SenseShift::Arduino::Input::AnalogSimpleSensor(CURL_PIN)); \ + NAME##_sensor->addFilters({ new ::SenseShift::Input::Filter::ExponentialMovingAverageFilter(0.8F) }); \ + if (CURL_INVERT) { \ + NAME##_sensor->addFilter({ new ::SenseShift::Input::Filter::AnalogInvertFilter() }); \ + } \ NAME##_sensor->setCalibrator((CURL_CALIB)); #ifdef PIN_FINGER_THUMB_SPLAY @@ -133,13 +136,14 @@ #define JOYSTICK_ENABLED false #endif -#define DEFINE_JOYSTICK_AXIS(NAME, PIN, INVERT, DEADZONE) \ - auto NAME##_sensor = \ - new ::SenseShift::Input::SimpleSensorDecorator(new ::SenseShift::Arduino::Input::AnalogSimpleSensor(PIN) \ - ); \ - NAME##_sensor->addFilters({ new ::SenseShift::Input::Filter::ExponentialMovingAverageFilter(0.7F), \ - new ::SenseShift::Input::Filter::CenterDeadzoneFilter(DEADZONE) }); - +#define DEFINE_JOYSTICK_AXIS(NAME, PIN, INVERT, DEADZONE) \ + auto NAME##_sensor = \ + new ::SenseShift::Input::SimpleSensorDecorator(new ::SenseShift::Arduino::Input::AnalogSimpleSensor(PIN)); \ + NAME##_sensor->addFilters({ new ::SenseShift::Input::Filter::ExponentialMovingAverageFilter(0.7F), \ + new ::SenseShift::Input::Filter::CenterDeadzoneFilter(DEADZONE) }); \ + if (INVERT) { \ + NAME##_sensor->addFilter({ new ::SenseShift::Input::Filter::AnalogInvertFilter() }); \ + } #pragma endregion #pragma region Buttons