diff --git a/lib/bno080/PinInterface.h b/lib/bno080/PinInterface.h index 77903b8..d2b6a4b 100644 --- a/lib/bno080/PinInterface.h +++ b/lib/bno080/PinInterface.h @@ -1,37 +1,37 @@ /* - SlimeVR Code is placed under the MIT license - Copyright (c) 2024 Eiren Rain & SlimeVR contributors + SlimeVR Code is placed under the MIT license + Copyright (c) 2024 Eiren Rain & SlimeVR contributors - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. */ #pragma once #include #include -class PinInterface -{ +class PinInterface { public: virtual bool init() { return true; }; virtual int digitalRead() = 0; virtual void pinMode(uint8_t mode) = 0; virtual void digitalWrite(uint8_t val) = 0; + virtual float analogRead() = 0; [[nodiscard]] virtual std::string toString() const = 0; }; diff --git a/src/sensorinterface/DirectPinInterface.cpp b/src/sensorinterface/DirectPinInterface.cpp index dc89c41..48f9ac5 100644 --- a/src/sensorinterface/DirectPinInterface.cpp +++ b/src/sensorinterface/DirectPinInterface.cpp @@ -26,4 +26,6 @@ int DirectPinInterface::digitalRead() { return ::digitalRead(_pinNum); } void DirectPinInterface::pinMode(uint8_t mode) { ::pinMode(_pinNum, mode); } -void DirectPinInterface::digitalWrite(uint8_t val) { ::digitalWrite(_pinNum, val); } \ No newline at end of file +void DirectPinInterface::digitalWrite(uint8_t val) { ::digitalWrite(_pinNum, val); } + +float DirectPinInterface::analogRead() { return ::analogRead(_pinNum); } diff --git a/src/sensorinterface/DirectPinInterface.h b/src/sensorinterface/DirectPinInterface.h index e794ad9..9335e0a 100644 --- a/src/sensorinterface/DirectPinInterface.h +++ b/src/sensorinterface/DirectPinInterface.h @@ -38,6 +38,7 @@ public: int digitalRead() override final; void pinMode(uint8_t mode) override final; void digitalWrite(uint8_t val) override final; + float analogRead() override final; [[nodiscard]] std::string toString() const final { using namespace std::string_literals; diff --git a/src/sensorinterface/MCP23X17PinInterface.cpp b/src/sensorinterface/MCP23X17PinInterface.cpp index 68eb9f5..bc59a42 100644 --- a/src/sensorinterface/MCP23X17PinInterface.cpp +++ b/src/sensorinterface/MCP23X17PinInterface.cpp @@ -28,4 +28,6 @@ void MCP23X17PinInterface::pinMode(uint8_t mode) { _mcp23x17->pinMode(_pinNum, m void MCP23X17PinInterface::digitalWrite(uint8_t val) { _mcp23x17->digitalWrite(_pinNum, val); -} \ No newline at end of file +} + +float MCP23X17PinInterface::analogRead() { return digitalRead() ? 1.0f : 0.0f; } diff --git a/src/sensorinterface/MCP23X17PinInterface.h b/src/sensorinterface/MCP23X17PinInterface.h index 260c625..db517e5 100644 --- a/src/sensorinterface/MCP23X17PinInterface.h +++ b/src/sensorinterface/MCP23X17PinInterface.h @@ -55,6 +55,7 @@ public: int digitalRead() override final; void pinMode(uint8_t mode) override final; void digitalWrite(uint8_t val) override final; + float analogRead() override final; [[nodiscard]] std::string toString() const final { using namespace std::string_literals; diff --git a/src/sensorinterface/ParallelMuxInterface.cpp b/src/sensorinterface/ParallelMuxInterface.cpp new file mode 100644 index 0000000..34de6b9 --- /dev/null +++ b/src/sensorinterface/ParallelMuxInterface.cpp @@ -0,0 +1,115 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include + +#include + +#include "ParallelMuxInterface.h" + +namespace SlimeVR { + +ParallelMuxInterface::ParallelMuxInterface( + PinInterface* dataPin, + std::vector& addressPins, + PinInterface* enablePin, + bool enableActiveLevel, + bool addressActiveLevel +) + : dataPin{dataPin} + , addressPins{addressPins} + , enablePin{enablePin} + , enableActiveLevel{enableActiveLevel} + , addressActiveLevel{addressActiveLevel} { + assert(addressPins.size() <= 8); +} + +bool ParallelMuxInterface::init() { + if (enablePin != nullptr) { + enablePin->pinMode(OUTPUT); + enablePin->digitalWrite(enableActiveLevel); + } + + for (auto* pin : addressPins) { + pin->pinMode(OUTPUT); + pin->digitalWrite(false); + } + + return true; +} + +void ParallelMuxInterface::pinMode(uint8_t mode) { dataPin->pinMode(mode); } + +void ParallelMuxInterface::digitalWrite(uint8_t address, uint8_t value) { + switchTo(address); + dataPin->digitalWrite(value); +} + +int ParallelMuxInterface::digitalRead(uint8_t address) { + switchTo(address); + return dataPin->digitalRead(); +} + +float ParallelMuxInterface::analogRead(uint8_t address) { + switchTo(address); + return dataPin->analogRead(); +} + +void ParallelMuxInterface::switchTo(uint8_t address) { + assert(address < 1 << addressPins.size()); + + if (address == currentAddress) { + return; + } + + if (enablePin != nullptr) { + enablePin->digitalWrite(!enableActiveLevel); + } + + for (auto* addressPin : addressPins) { + bool value = address & 0x01; + address >>= 1; + + addressPin->digitalWrite(value); + } + + if (enablePin != nullptr) { + enablePin->digitalWrite(enableActiveLevel); + } + + currentAddress = address; + delay(1); +} + +std::string ParallelMuxInterface::toString() const { + std::string result = "Mux({"; + for (size_t i = 0; i < addressPins.size(); i++) { + if (i != 0) { + result += ", "; + } + result += addressPins[i]->toString(); + } + result += "}, "; + result += dataPin->toString(); + result += ")"; + return result; +} + +} // namespace SlimeVR diff --git a/src/sensorinterface/ParallelMuxInterface.h b/src/sensorinterface/ParallelMuxInterface.h new file mode 100644 index 0000000..6dfcf08 --- /dev/null +++ b/src/sensorinterface/ParallelMuxInterface.h @@ -0,0 +1,59 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#pragma once + +#include + +#include +#include + +namespace SlimeVR { + +class ParallelMuxInterface { +public: + ParallelMuxInterface( + PinInterface* dataPin, + std::vector& addressPins, + PinInterface* enablePin = nullptr, + bool enableActiveLevel = false, + bool addressActiveLevel = true + ); + + bool init(); + void pinMode(uint8_t mode); + void digitalWrite(uint8_t address, uint8_t value); + int digitalRead(uint8_t address); + float analogRead(uint8_t address); + + [[nodiscard]] std::string toString() const; + +private: + void switchTo(uint8_t address); + + PinInterface* const dataPin; + const std::vector addressPins; + PinInterface* const enablePin = nullptr; + const bool enableActiveLevel = false; + const bool addressActiveLevel = true; + uint8_t currentAddress = 0; +}; + +} // namespace SlimeVR diff --git a/src/sensorinterface/ParallelMuxPin.cpp b/src/sensorinterface/ParallelMuxPin.cpp new file mode 100644 index 0000000..2db717d --- /dev/null +++ b/src/sensorinterface/ParallelMuxPin.cpp @@ -0,0 +1,40 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#include + +#include "ParallelMuxPin.h" + +namespace SlimeVR { + +ParallelMuxPin::ParallelMuxPin(ParallelMuxInterface* mux, uint8_t address) + : mux{mux} + , address{address} {} + +void ParallelMuxPin::pinMode(uint8_t mode) { mux->pinMode(mode); } +void ParallelMuxPin::digitalWrite(uint8_t value) { mux->digitalWrite(address, value); } +int ParallelMuxPin::digitalRead() { return mux->digitalRead(address); } +float ParallelMuxPin::analogRead() { return mux->analogRead(address); } + +std::string ParallelMuxPin::toString() const { + return "MuxPin(" + mux->toString() + ", " + std::to_string(address) + ")"; +} + +} // namespace SlimeVR diff --git a/src/sensorinterface/ParallelMuxPin.h b/src/sensorinterface/ParallelMuxPin.h new file mode 100644 index 0000000..dfbd0ad --- /dev/null +++ b/src/sensorinterface/ParallelMuxPin.h @@ -0,0 +1,45 @@ +/* + SlimeVR Code is placed under the MIT license + Copyright (c) 2025 Gorbit99 & SlimeVR Contributors + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + THE SOFTWARE. +*/ + +#pragma once + +#include + +#include "ParallelMuxInterface.h" +#include "PinInterface.h" +namespace SlimeVR { + +class ParallelMuxPin : public PinInterface { +public: + ParallelMuxPin(ParallelMuxInterface* mux, uint8_t address); + + void pinMode(uint8_t mode) final; + void digitalWrite(uint8_t value) final; + int digitalRead() final; + float analogRead() final; + + [[nodiscard]] std::string toString() const final; + +private: + ParallelMuxInterface* const mux; + uint8_t address; +}; + +} // namespace SlimeVR diff --git a/src/sensorinterface/SensorInterfaceManager.h b/src/sensorinterface/SensorInterfaceManager.h index 843a4b5..c0c1cd6 100644 --- a/src/sensorinterface/SensorInterfaceManager.h +++ b/src/sensorinterface/SensorInterfaceManager.h @@ -34,6 +34,8 @@ #include "I2CPCAInterface.h" #include "I2CWireSensorInterface.h" #include "MCP23X17PinInterface.h" +#include "ParallelMuxInterface.h" +#include "ParallelMuxPin.h" #include "SPIImpl.h" #include "SensorInterface.h" #include "i2cimpl.h" @@ -97,6 +99,8 @@ public: inline auto& i2cImpl() { return i2cImpls; } inline auto& directSPIInterface() { return directSPIInterfaces; } inline auto& spiImpl() { return spiImpls; } + inline auto& parallelMuxInterface() { return parallelMuxInterfaces; } + inline auto& parallelMuxPinInterface() { return parallelMuxPinInterfaces; } private: SensorInterface directPinInterfaces{[](int pin) { @@ -108,6 +112,16 @@ private: SensorInterface i2cImpls; SensorInterface directSPIInterfaces; SensorInterface spiImpls; + SensorInterface< + ParallelMuxInterface, + PinInterface*, + std::vector, + PinInterface*, + bool, + bool> + parallelMuxInterfaces; + SensorInterface + parallelMuxPinInterfaces; }; } // namespace SlimeVR diff --git a/src/sensors/SensorBuilder.cpp b/src/sensors/SensorBuilder.cpp index 3c20e4b..93474f6 100644 --- a/src/sensors/SensorBuilder.cpp +++ b/src/sensors/SensorBuilder.cpp @@ -60,6 +60,24 @@ uint8_t SensorBuilder::buildAllSensors() { SPISettings(clockFreq, bitOrder, dataMode) ); }; + [[maybe_unused]] static auto MUX_PIN + = [&](PinInterface* data, + std::vector&& addressPins, + uint8_t channel, + PinInterface* enablePin = nullptr, + bool enableActiveLevel = false, + bool addressActiveLevel = true) constexpr { + return interfaceManager.parallelMuxPinInterface().get( + interfaceManager.parallelMuxInterface().get( + data, + addressPins, + enablePin, + enableActiveLevel, + addressActiveLevel + ), + channel + ); + }; // Apply descriptor list and expand to entries SENSOR_DESC_LIST