From 47b2d5e7530da4c940fc99e606cfad0c6a0638a2 Mon Sep 17 00:00:00 2001 From: Pieter Pas Date: Sat, 28 May 2022 02:25:33 +0200 Subject: [PATCH] =?UTF-8?q?Refactor=20Encoder=20code,=20Encoder=20?= =?UTF-8?q?=E2=86=92=20AHEncoder?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../RotaryEncoder/RotaryEncoder.ino | 2 +- mock/Libraries/Encoder/Encoder.h | 9 +- .../Abstract/MIDIAbsoluteEncoder.hpp | 6 +- .../Abstract/MIDIRotaryEncoder.hpp | 6 +- .../Bankable/Abstract/MIDIAbsoluteEncoder.hpp | 6 +- .../Bankable/Abstract/MIDIRotaryEncoder.hpp | 6 +- .../Bankable/CCAbsoluteEncoder.hpp | 2 +- src/MIDI_Outputs/Bankable/CCRotaryEncoder.hpp | 2 +- .../Bankable/PBAbsoluteEncoder.hpp | 2 +- src/MIDI_Outputs/CCAbsoluteEncoder.hpp | 2 +- src/MIDI_Outputs/CCRotaryEncoder.hpp | 4 +- .../ManyAddresses/CCAbsoluteEncoder.hpp | 2 +- .../ManyAddresses/CCRotaryEncoder.hpp | 2 +- .../ManyAddresses/PBAbsoluteEncoder.hpp | 2 +- src/MIDI_Outputs/PBAbsoluteEncoder.hpp | 2 +- src/Selectors/EncoderSelector.hpp | 4 +- src/Submodules/Encoder/AHEncoder.cpp | 136 +++++++ src/Submodules/Encoder/AHEncoder.hpp | 92 +++++ .../Encoder/{Encoder.ipp => AHEncoder.ipp} | 71 ++-- src/Submodules/Encoder/AtomicPosition.hpp | 166 ++++++++ src/Submodules/Encoder/DirectPinRead.hpp | 107 ++++++ src/Submodules/Encoder/Encoder-AVR.ipp | 160 -------- src/Submodules/Encoder/Encoder.cpp | 118 ------ src/Submodules/Encoder/Encoder.h | 134 ------- src/Submodules/Encoder/NumInterrupts.hpp | 100 +++++ src/Submodules/Encoder/README.md | 6 +- src/Submodules/Encoder/codegen/ISRs-def.ipp | 129 ++++--- src/Submodules/Encoder/codegen/ISRs.py | 17 +- .../Encoder/utility/direct_pin_read.h | 127 ------- .../Encoder/utility/interrupt_pins.h | 358 ------------------ src/Submodules/Encoder/utility/move.h | 29 -- 31 files changed, 737 insertions(+), 1072 deletions(-) create mode 100644 src/Submodules/Encoder/AHEncoder.cpp create mode 100644 src/Submodules/Encoder/AHEncoder.hpp rename src/Submodules/Encoder/{Encoder.ipp => AHEncoder.ipp} (64%) create mode 100644 src/Submodules/Encoder/AtomicPosition.hpp create mode 100644 src/Submodules/Encoder/DirectPinRead.hpp delete mode 100644 src/Submodules/Encoder/Encoder-AVR.ipp delete mode 100644 src/Submodules/Encoder/Encoder.cpp delete mode 100644 src/Submodules/Encoder/Encoder.h create mode 100644 src/Submodules/Encoder/NumInterrupts.hpp delete mode 100644 src/Submodules/Encoder/utility/direct_pin_read.h delete mode 100644 src/Submodules/Encoder/utility/interrupt_pins.h delete mode 100644 src/Submodules/Encoder/utility/move.h diff --git a/examples/1. MIDI Output/3. Rotary Encoders/RotaryEncoder/RotaryEncoder/RotaryEncoder.ino b/examples/1. MIDI Output/3. Rotary Encoders/RotaryEncoder/RotaryEncoder/RotaryEncoder.ino index ff0a7f9250..11d28e20f0 100644 --- a/examples/1. MIDI Output/3. Rotary Encoders/RotaryEncoder/RotaryEncoder/RotaryEncoder.ino +++ b/examples/1. MIDI Output/3. Rotary Encoders/RotaryEncoder/RotaryEncoder/RotaryEncoder.ino @@ -3,7 +3,7 @@ * can be used for changing effect parameters, volumes, pan and balance * controls, etc. * - * @boards AVR, AVR USB, Nano Every, Due, Nano 33 IoT, Nano 33 BLE, Pi Pico, Teensy 3.x, ESP32 + * @boards AVR, AVR USB, Nano Every, Due, Nano 33 IoT, Nano 33 BLE, Pi Pico, Teensy 3.x, ESP32, ESP8266 * * Connections * ----------- diff --git a/mock/Libraries/Encoder/Encoder.h b/mock/Libraries/Encoder/Encoder.h index 9bfc3e004b..4c7a9508d9 100644 --- a/mock/Libraries/Encoder/Encoder.h +++ b/mock/Libraries/Encoder/Encoder.h @@ -7,11 +7,12 @@ class EncoderMock { MOCK_CONST_METHOD0(read, long()); }; -class Encoder { +class AHEncoder { public: - Encoder(int, int) : mock(nullptr) {} - Encoder(const EncoderMock &mock) : mock(&mock) {} - Encoder(const Encoder &) = default; + AHEncoder(int, int) : mock(nullptr) {} + AHEncoder(const EncoderMock &mock) : mock(&mock) {} + AHEncoder(EncoderMock &&) = delete; + AHEncoder(const AHEncoder &) = default; long read() const { return mock ? mock->read() : 0; } private: diff --git a/src/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp b/src/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp index fd59c82b5f..a37b8aa058 100644 --- a/src/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/Abstract/MIDIAbsoluteEncoder.hpp @@ -8,7 +8,7 @@ #include #ifdef ARDUINO -#include +#include #else #include // Mock #endif @@ -85,11 +85,11 @@ class GenericMIDIAbsoluteEncoder : public MIDIOutputElement { }; template -using MIDIAbsoluteEncoder = GenericMIDIAbsoluteEncoder; +using MIDIAbsoluteEncoder = GenericMIDIAbsoluteEncoder; template using BorrowedMIDIAbsoluteEncoder = - GenericMIDIAbsoluteEncoder; + GenericMIDIAbsoluteEncoder; END_CS_NAMESPACE diff --git a/src/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp b/src/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp index ae559269c9..41a221e64e 100644 --- a/src/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp +++ b/src/MIDI_Outputs/Abstract/MIDIRotaryEncoder.hpp @@ -7,7 +7,7 @@ #include #ifdef ARDUINO -#include +#include #else #include // Mock #endif @@ -62,10 +62,10 @@ class GenericMIDIRotaryEncoder : public MIDIOutputElement { }; template -using MIDIRotaryEncoder = GenericMIDIRotaryEncoder; +using MIDIRotaryEncoder = GenericMIDIRotaryEncoder; template -using BorrowedMIDIRotaryEncoder = GenericMIDIRotaryEncoder; +using BorrowedMIDIRotaryEncoder = GenericMIDIRotaryEncoder; END_CS_NAMESPACE diff --git a/src/MIDI_Outputs/Bankable/Abstract/MIDIAbsoluteEncoder.hpp b/src/MIDI_Outputs/Bankable/Abstract/MIDIAbsoluteEncoder.hpp index 47bd0bb914..e835e670c6 100644 --- a/src/MIDI_Outputs/Bankable/Abstract/MIDIAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/Bankable/Abstract/MIDIAbsoluteEncoder.hpp @@ -8,7 +8,7 @@ #include #ifdef ARDUINO -#include +#include #else #include // Mock #endif @@ -98,11 +98,11 @@ class GenericMIDIAbsoluteEncoder : public MIDIOutputElement { template using MIDIAbsoluteEncoder = - GenericMIDIAbsoluteEncoder; + GenericMIDIAbsoluteEncoder; template using BorrowedMIDIAbsoluteEncoder = - GenericMIDIAbsoluteEncoder; + GenericMIDIAbsoluteEncoder; } // namespace Bankable diff --git a/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp b/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp index d347679a82..5a95bff3c8 100644 --- a/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp +++ b/src/MIDI_Outputs/Bankable/Abstract/MIDIRotaryEncoder.hpp @@ -8,7 +8,7 @@ #include #ifdef ARDUINO -#include +#include #else #include // Mock #endif @@ -63,11 +63,11 @@ class GenericMIDIRotaryEncoder : public MIDIOutputElement { template using MIDIRotaryEncoder = - GenericMIDIRotaryEncoder; + GenericMIDIRotaryEncoder; template using BorrowedMIDIRotaryEncoder = - GenericMIDIRotaryEncoder; + GenericMIDIRotaryEncoder; } // namespace Bankable diff --git a/src/MIDI_Outputs/Bankable/CCAbsoluteEncoder.hpp b/src/MIDI_Outputs/Bankable/CCAbsoluteEncoder.hpp index b0f4016363..b3d0f0b061 100644 --- a/src/MIDI_Outputs/Bankable/CCAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/Bankable/CCAbsoluteEncoder.hpp @@ -55,7 +55,7 @@ class CCAbsoluteEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCAbsoluteEncoder(BankConfig config, Encoder &&encoder, + CCAbsoluteEncoder(BankConfig config, AHEncoder &&encoder, MIDIAddress address, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder( diff --git a/src/MIDI_Outputs/Bankable/CCRotaryEncoder.hpp b/src/MIDI_Outputs/Bankable/CCRotaryEncoder.hpp index aff88a89c3..e68373bd4f 100644 --- a/src/MIDI_Outputs/Bankable/CCRotaryEncoder.hpp +++ b/src/MIDI_Outputs/Bankable/CCRotaryEncoder.hpp @@ -51,7 +51,7 @@ class CCRotaryEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCRotaryEncoder(OutputBankConfig<> config, Encoder &&encoder, + CCRotaryEncoder(OutputBankConfig<> config, AHEncoder &&encoder, MIDIAddress address, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIRotaryEncoder( diff --git a/src/MIDI_Outputs/Bankable/PBAbsoluteEncoder.hpp b/src/MIDI_Outputs/Bankable/PBAbsoluteEncoder.hpp index 39a2802aee..69098e3073 100644 --- a/src/MIDI_Outputs/Bankable/PBAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/Bankable/PBAbsoluteEncoder.hpp @@ -57,7 +57,7 @@ class PBAbsoluteEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - PBAbsoluteEncoder(const BankConfig &config, Encoder &&encoder, + PBAbsoluteEncoder(const BankConfig &config, AHEncoder &&encoder, MIDIChannelCable address, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder>( diff --git a/src/MIDI_Outputs/CCAbsoluteEncoder.hpp b/src/MIDI_Outputs/CCAbsoluteEncoder.hpp index 30b315a9a5..4bf1ff1188 100644 --- a/src/MIDI_Outputs/CCAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/CCAbsoluteEncoder.hpp @@ -42,7 +42,7 @@ class CCAbsoluteEncoder : public MIDIAbsoluteEncoder { * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCAbsoluteEncoder(Encoder &&encoder, MIDIAddress address, + CCAbsoluteEncoder(AHEncoder &&encoder, MIDIAddress address, int16_t multiplier = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder( std::move(encoder), address, multiplier, pulsesPerStep, {}) {} diff --git a/src/MIDI_Outputs/CCRotaryEncoder.hpp b/src/MIDI_Outputs/CCRotaryEncoder.hpp index a9db3988c1..4b8aa695b6 100644 --- a/src/MIDI_Outputs/CCRotaryEncoder.hpp +++ b/src/MIDI_Outputs/CCRotaryEncoder.hpp @@ -43,7 +43,7 @@ class CCRotaryEncoder : public MIDIRotaryEncoder { * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCRotaryEncoder(Encoder &&encoder, MIDIAddress address, + CCRotaryEncoder(AHEncoder &&encoder, MIDIAddress address, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIRotaryEncoder( std::move(encoder), address, speedMultiply, pulsesPerStep, {}) {} @@ -86,7 +86,7 @@ class BorrowedCCRotaryEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - BorrowedCCRotaryEncoder(Encoder &encoder, MIDIAddress address, + BorrowedCCRotaryEncoder(AHEncoder &encoder, MIDIAddress address, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : BorrowedMIDIRotaryEncoder( encoder, address, speedMultiply, pulsesPerStep, {}) {} diff --git a/src/MIDI_Outputs/ManyAddresses/CCAbsoluteEncoder.hpp b/src/MIDI_Outputs/ManyAddresses/CCAbsoluteEncoder.hpp index f570dbc906..227b81f742 100644 --- a/src/MIDI_Outputs/ManyAddresses/CCAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/ManyAddresses/CCAbsoluteEncoder.hpp @@ -57,7 +57,7 @@ class CCAbsoluteEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCAbsoluteEncoder(const Bank &bank, Encoder &&encoder, + CCAbsoluteEncoder(const Bank &bank, AHEncoder &&encoder, const Array &addresses, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder, diff --git a/src/MIDI_Outputs/ManyAddresses/CCRotaryEncoder.hpp b/src/MIDI_Outputs/ManyAddresses/CCRotaryEncoder.hpp index 58228e9480..f62c80a52e 100644 --- a/src/MIDI_Outputs/ManyAddresses/CCRotaryEncoder.hpp +++ b/src/MIDI_Outputs/ManyAddresses/CCRotaryEncoder.hpp @@ -52,7 +52,7 @@ class CCRotaryEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - CCRotaryEncoder(const Bank &bank, Encoder &&encoder, + CCRotaryEncoder(const Bank &bank, AHEncoder &&encoder, const Array &addresses, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIRotaryEncoder, RelativeCCSender>( diff --git a/src/MIDI_Outputs/ManyAddresses/PBAbsoluteEncoder.hpp b/src/MIDI_Outputs/ManyAddresses/PBAbsoluteEncoder.hpp index 3918e4ba07..981b19e8e0 100644 --- a/src/MIDI_Outputs/ManyAddresses/PBAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/ManyAddresses/PBAbsoluteEncoder.hpp @@ -58,7 +58,7 @@ class PBAbsoluteEncoder * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - PBAbsoluteEncoder(const Bank &bank, Encoder &&encoder, + PBAbsoluteEncoder(const Bank &bank, AHEncoder &&encoder, const Array &addresses, int16_t speedMultiply = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder, diff --git a/src/MIDI_Outputs/PBAbsoluteEncoder.hpp b/src/MIDI_Outputs/PBAbsoluteEncoder.hpp index bd55c8f279..256d80ce28 100644 --- a/src/MIDI_Outputs/PBAbsoluteEncoder.hpp +++ b/src/MIDI_Outputs/PBAbsoluteEncoder.hpp @@ -43,7 +43,7 @@ class PBAbsoluteEncoder : public MIDIAbsoluteEncoder> { * speed, increasing the number of pulsesPerStep will result in a * lower speed. */ - PBAbsoluteEncoder(Encoder &&encoder, MIDIChannelCable address, + PBAbsoluteEncoder(AHEncoder &&encoder, MIDIChannelCable address, int16_t multiplier = 1, uint8_t pulsesPerStep = 4) : MIDIAbsoluteEncoder>( std::move(encoder), address, multiplier, pulsesPerStep, {}) {} diff --git a/src/Selectors/EncoderSelector.hpp b/src/Selectors/EncoderSelector.hpp index 7755314df2..0e3c8339b8 100644 --- a/src/Selectors/EncoderSelector.hpp +++ b/src/Selectors/EncoderSelector.hpp @@ -6,7 +6,7 @@ #include #ifdef ARDUINO -#include +#include #else #include // Mock #endif @@ -58,7 +58,7 @@ class GenericEncoderSelector : public GenericSelector { } private: - Encoder encoder; + AHEncoder encoder; pin_t switchPin; int8_t pulsesPerStep; Wrap wrap; diff --git a/src/Submodules/Encoder/AHEncoder.cpp b/src/Submodules/Encoder/AHEncoder.cpp new file mode 100644 index 0000000000..6c0ed20da0 --- /dev/null +++ b/src/Submodules/Encoder/AHEncoder.cpp @@ -0,0 +1,136 @@ +#ifdef ARDUINO + +#include "AHEncoder.hpp" + +#include // std::swap + +BEGIN_CS_NAMESPACE + +#include "codegen/ISRs-def.ipp" + +AHEncoder::AHEncoder(uint8_t pinA, uint8_t pinB) + : pins {pinA, pinB}, direct_pins {direct_pin_read(pinA), + direct_pin_read(pinB)} { + // It's much faster to use the GPIO registers directly, rather than + // calling digitalRead every time we need to read a pin. + // digitalRead looks up the register and bitmasks every time it's called + // but here, we look them up once in the constructor. +} + +AHEncoder::AHEncoder(AHEncoder &&other) { swap(*this, other); } + +AHEncoder &AHEncoder::operator=(AHEncoder &&other) { + swap(*this, other); + return *this; +} + +void swap(AHEncoder &a, AHEncoder &b) { + // First swap the normal member variables: + std::swap(a.interrupts_in_use, b.interrupts_in_use); + std::swap(a.pins, b.pins); + + // Next, update the pointers in interruptArgs: + // When interrupts are in use, there is a global interrupt context + // variable that holds a pointer to the encoders that are being swapped + // or moved. + // After moving, this pointer would no longer be valid, so it has to be + // changed to point to the new encoder object. + // Calling attachInterrupt is not necessary, because this should already + // have happened in the begin method if interrupts_in_use is nonzero. + // Before messing with the state variables that can be changed or + // accessed from within an ISR, we have to disable interrupts. + noInterrupts(); + std::swap(a.state, b.state); + std::swap(a.direct_pins, b.direct_pins); + std::swap(a.position, b.position); + if (a.interrupts_in_use > 0) { + int int1 = digitalPinToInterrupt(a.pins[0]); + if (int1 != NOT_AN_INTERRUPT) + AHEncoder::interruptArgs[int1] = &a; + int int2 = digitalPinToInterrupt(a.pins[1]); + if (int2 != NOT_AN_INTERRUPT) + AHEncoder::interruptArgs[int2] = &a; + } + if (b.interrupts_in_use > 0) { + int int1 = digitalPinToInterrupt(b.pins[0]); + if (int1 != NOT_AN_INTERRUPT) + AHEncoder::interruptArgs[int1] = &b; + int int2 = digitalPinToInterrupt(b.pins[1]); + if (int2 != NOT_AN_INTERRUPT) + AHEncoder::interruptArgs[int2] = &b; + } + interrupts(); +} + +AHEncoder::~AHEncoder() { + // If interrupts are in use, there are dangling pointers to the encoder + // state in the global interrupt contexts. These have to be detached + // when the encoder object is removed. + end(); +} + +void AHEncoder::begin() { + pinMode(pins[0], INPUT_PULLUP); + pinMode(pins[1], INPUT_PULLUP); + // allow time for a passive R-C filter to charge + // through the pullup resistors, before reading + // the initial state + delayMicroseconds(2000); + uint8_t s = 0; + if (direct_pins[0].read()) + s |= 1; + if (direct_pins[1].read()) + s |= 2; + state = s; + + attachInterruptCtx(digitalPinToInterrupt(pins[0])); + attachInterruptCtx(digitalPinToInterrupt(pins[1])); +#if defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040) + // https://github.com/arduino/ArduinoCore-mbed/issues/253 + pinMode(pins[0], INPUT_PULLUP); + pinMode(pins[1], INPUT_PULLUP); +#endif +} + +void AHEncoder::end() { + if (interrupts_in_use > 0) { + detachInterruptCtx(digitalPinToInterrupt(pins[0])); + detachInterruptCtx(digitalPinToInterrupt(pins[1])); + } +} + +void AHEncoder::attachInterruptCtx(int interrupt) { + if (interrupt != NOT_AN_INTERRUPT) { + interruptArgs[interrupt] = this; + ++interrupts_in_use; +#ifdef ARDUINO_ARCH_RP2040 + gpio_set_irq_enabled_with_callback( + interrupt, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, true, + [](uint gpio, uint32_t) { + if (auto arg = interruptArgs[gpio]) + arg->update(); + }); +#else + attachInterrupt(interrupt, EncoderISRs::getISR(interrupt), CHANGE); +#endif + } +} + +void AHEncoder::detachInterruptCtx(int interrupt) { + if (interrupt != NOT_AN_INTERRUPT) { +#ifdef ARDUINO_ARCH_RP2040 + gpio_set_irq_enabled(interrupt, GPIO_IRQ_EDGE_FALL | GPIO_IRQ_EDGE_RISE, + false); +#else + detachInterrupt(interrupt); +#endif + --interrupts_in_use; + interruptArgs[interrupt] = nullptr; + } +} + +AHEncoder *AHEncoder::interruptArgs[CS_ENCODER_ARGLIST_SIZE] {}; + +END_CS_NAMESPACE + +#endif \ No newline at end of file diff --git a/src/Submodules/Encoder/AHEncoder.hpp b/src/Submodules/Encoder/AHEncoder.hpp new file mode 100644 index 0000000000..42e940c58c --- /dev/null +++ b/src/Submodules/Encoder/AHEncoder.hpp @@ -0,0 +1,92 @@ +#pragma once + +#include "AtomicPosition.hpp" +#include "DirectPinRead.hpp" +#include "NumInterrupts.hpp" + +BEGIN_CS_NAMESPACE + +// Use IRAM_ATTR for ISRs to prevent ESP8266 resets +#if defined(ESP8266) || defined(ESP32) +#define CS_ENCODER_ISR_ATTR IRAM_ATTR +#else +#define CS_ENCODER_ISR_ATTR +#endif + +// Largest interrupt number. +#define CS_ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT + +/// Class for reading quadrature encoders, heavily influenced by +/// http://www.pjrc.com/teensy/td_libs_Encoder.html +class AHEncoder { + public: + /** + * @brief Constructor. + * + * @param pinA + * The first pin, connected to the encoder's "A" pin. + * @param pinB + * The second pin, connected to the encoder's "B" pin. + * + * The internal pull-up resistors will be enabled on these pins upon + * initialization (when calling the `begin` method). + */ + AHEncoder(uint8_t pinA, uint8_t pinB); + + /// Copy constructor: copying an Encoder object is semantically meaningless, + /// so it has been deleted. + AHEncoder(const AHEncoder &) = delete; + /// Copy assignment: copying an Encoder object is semantically meaningless, + /// so it has been deleted. + AHEncoder &operator=(const AHEncoder &) = delete; + /// Swap two Encoder objects. + friend void swap(AHEncoder &a, AHEncoder &b); + + /// Move constructor. + AHEncoder(AHEncoder &&other); + /// Move assignment. + AHEncoder &operator=(AHEncoder &&other); + + /// Destructor, detaches the interrupts. + ~AHEncoder(); + + /// Initialize this encoder by enabling the pull-up resistors and attaching + /// the interrupts handlers (if interrupts are enabled and available on the + /// the given pins). + void begin(); + /// Disable the interrupts used by this encoder. + void end(); + + public: + /// Read the current absolute position of the encoder. + int32_t read(); + /// Read the current absolute position of the encoder and reset it to zero + /// afterwards. + int32_t readAndReset(int32_t newpos = 0); + /// Set the absolute position to the given value. + void write(int32_t p); + + private: + void attachInterruptCtx(int interrupt); + void detachInterruptCtx(int interrupt); + + private: + uint8_t pins[2]; + uint8_t interrupts_in_use = 0; + uint8_t state = 0; + DirectPinRead direct_pins[2]; + AtomicPosition position {0}; + + public: + /// `update()` is not meant to be called from outside Encoder, + /// but it is public to allow static interrupt routines. + /// DO NOT call update() directly from sketches. + CS_ENCODER_ISR_ATTR void update(); + /// Similarly to `update()`, don't use these interrupt handler arguments + /// from your sketch. + static AHEncoder *interruptArgs[CS_ENCODER_ARGLIST_SIZE]; +}; + +END_CS_NAMESPACE + +#include "AHEncoder.ipp" diff --git a/src/Submodules/Encoder/Encoder.ipp b/src/Submodules/Encoder/AHEncoder.ipp similarity index 64% rename from src/Submodules/Encoder/Encoder.ipp rename to src/Submodules/Encoder/AHEncoder.ipp index 23af857c15..8894dc8409 100644 --- a/src/Submodules/Encoder/Encoder.ipp +++ b/src/Submodules/Encoder/AHEncoder.ipp @@ -1,36 +1,25 @@ -#include "Encoder.h" +#pragma once + +#include "AHEncoder.hpp" BEGIN_CS_NAMESPACE -inline int32_t Encoder::read() { - if (interrupts_in_use < 2) { - noInterrupts(); - update(&encoder); - } else { - noInterrupts(); - } - int32_t ret = encoder.position; - interrupts(); - return ret; +inline int32_t AHEncoder::read() { + if (interrupts_in_use < 2) + update(); + return position.get(); } -inline int32_t Encoder::readAndReset() { - if (interrupts_in_use < 2) { - noInterrupts(); - update(&encoder); - } else { - noInterrupts(); - } - int32_t ret = encoder.position; - encoder.position = 0; - interrupts(); - return ret; +inline int32_t AHEncoder::readAndReset(int32_t newpos) { + if (interrupts_in_use < 2) + update(); + return position.xchg(newpos); } -inline void Encoder::write(int32_t p) { - noInterrupts(); - encoder.position = p; - interrupts(); +inline void AHEncoder::write(int32_t p) { + if (interrupts_in_use < 2) + update(); + position.set(p); } // _______ _______ @@ -81,33 +70,27 @@ inline void Encoder::write(int32_t p) { } */ -#if defined(__AVR__) -#include "Encoder-AVR.ipp" -#else -inline void Encoder::update(Encoder_internal_state_t *arg) { - uint8_t p1val = DIRECT_PIN_READ(arg->pin1_register, arg->pin1_bitmask); - uint8_t p2val = DIRECT_PIN_READ(arg->pin2_register, arg->pin2_bitmask); - uint8_t state = arg->state & 3; - if (p1val) - state |= 4; - if (p2val) - state |= 8; - arg->state = (state >> 2); - switch (state) { +inline void AHEncoder::update() { + uint8_t s = state & 0b11; + if (direct_pins[0].read()) + s |= 4; + if (direct_pins[1].read()) + s |= 8; + state = (s >> 2); + switch (s) { case 1: case 7: case 8: - case 14: arg->position++; return; + case 14: position.add_isr(1); return; case 2: case 4: case 11: - case 13: arg->position--; return; + case 13: position.add_isr(-1); return; case 3: - case 12: arg->position += 2; return; + case 12: position.add_isr(2); return; case 6: - case 9: arg->position -= 2; return; + case 9: position.add_isr(-2); return; } } -#endif END_CS_NAMESPACE diff --git a/src/Submodules/Encoder/AtomicPosition.hpp b/src/Submodules/Encoder/AtomicPosition.hpp new file mode 100644 index 0000000000..0f9612a2df --- /dev/null +++ b/src/Submodules/Encoder/AtomicPosition.hpp @@ -0,0 +1,166 @@ +#pragma once + +#include +#include + +#ifdef __AVR__ +#include +#else +#include +#endif +#ifdef ARDUINO_ARCH_MBED +#include +#endif + +BEGIN_CS_NAMESPACE + +#if defined(ATOMIC_INT_LOCK_FREE) && ATOMIC_INT_LOCK_FREE == 2 +template +struct AtomicPosition { + using type = T; + std::atomic value {}; + + AtomicPosition(T t) : value {t} {} + AtomicPosition(const AtomicPosition &o) : AtomicPosition {o.get()} {} + AtomicPosition(AtomicPosition &&o) : AtomicPosition {o.get()} {} + AtomicPosition &operator=(const AtomicPosition &o) { + this->set(o.get()); + return *this; + } + AtomicPosition &operator=(AtomicPosition &&o) { + this->set(o.get()); + return *this; + } + + constexpr static std::memory_order mo_rlx = std::memory_order_relaxed; + void add(type other) { value.fetch_add(other, mo_rlx); } + type get() const { return value.load(mo_rlx); } + void set(type other) { value.store(other, mo_rlx); } + type xchg(type other) { return value.exchange(other, mo_rlx); } + void add_isr(type other) { add(other); } +}; +#elif defined(__AVR__) +template +struct AtomicPosition { + using type = T; + volatile type value; + + AtomicPosition(T t) : value {t} {} + AtomicPosition(const AtomicPosition &o) : AtomicPosition {o.get()} {} + AtomicPosition(AtomicPosition &&o) : AtomicPosition {o.get()} {} + AtomicPosition &operator=(const AtomicPosition &o) { + this->set(o.get()); + return *this; + } + AtomicPosition &operator=(AtomicPosition &&o) { + this->set(o.get()); + return *this; + } + + void add(type other) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { value += other; } + } + type get() const { + type copy; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { copy = value; } + return copy; + } + void set(type other) { + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { value = other; } + } + type xchg(type other) { + type copy; + ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { + copy = value; + value = other; + } + return copy; + } + void add_isr(type other) { value += other; } +}; +#elif defined(ARDUINO_ARCH_MBED) +template +struct AtomicPosition { + using type = T; + volatile type value; + + AtomicPosition(T t) : value {t} {} + AtomicPosition(const AtomicPosition &o) : AtomicPosition {o.get()} {} + AtomicPosition(AtomicPosition &&o) : AtomicPosition {o.get()} {} + AtomicPosition &operator=(const AtomicPosition &o) { + this->set(o.get()); + return *this; + } + AtomicPosition &operator=(AtomicPosition &&o) { + this->set(o.get()); + return *this; + } + + void add(type other) { + mbed::CriticalSectionLock lck; + value += other; + } + type get() const { + mbed::CriticalSectionLock lck; + return value; + } + void set(type other) { + mbed::CriticalSectionLock lck; + value = other; + } + type xchg(type other) { + mbed::CriticalSectionLock lck; + type copy = value; + value = other; + return copy; + } + void add_isr(type other) { value += other; } +}; +#else +template +struct AtomicPosition { + using type = T; + volatile type value; + + AtomicPosition(T t) : value {t} {} + AtomicPosition(const AtomicPosition &o) : AtomicPosition {o.get()} {} + AtomicPosition(AtomicPosition &&o) : AtomicPosition {o.get()} {} + AtomicPosition &operator=(const AtomicPosition &o) { + this->set(o.get()); + return *this; + } + AtomicPosition &operator=(AtomicPosition &&o) { + this->set(o.get()); + return *this; + } + + void add(type other) { + noInterrupts(); + value += other; + interrupts(); + } + type get() const { + type copy; + noInterrupts(); + copy = value; + interrupts(); + return copy; + } + void set(type other) { + noInterrupts(); + value = other; + interrupts(); + } + type xchg(type other) { + type copy; + noInterrupts(); + copy = value; + value = other; + interrupts(); + return copy; + } + void add_isr(type other) { value += other; } +}; +#endif + +END_CS_NAMESPACE \ No newline at end of file diff --git a/src/Submodules/Encoder/DirectPinRead.hpp b/src/Submodules/Encoder/DirectPinRead.hpp new file mode 100644 index 0000000000..0e6dee4c29 --- /dev/null +++ b/src/Submodules/Encoder/DirectPinRead.hpp @@ -0,0 +1,107 @@ +#pragma once + +#include +#include + +#include +#include + +#ifdef ARDUINO_ARCH_NRF52840 +#include +#endif + +BEGIN_CS_NAMESPACE + +template +struct DirectPinReadReg { + RegisterType *in_reg; + typename std::remove_cv::type bitmask; + bool read() const { return *in_reg & bitmask; } +}; + +// 8-bit AVR +#if defined(__AVR__) || \ + (defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL))) + +using DirectPinRead = DirectPinReadReg; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {portInputRegister(digitalPinToPort(pin)), + static_cast(digitalPinToBitMask(pin))}; +} + +// 32-bit +#elif defined(__SAM3X8E__) || defined(ESP32) || defined(ESP8266) || \ + defined(__SAMD51__) + +using DirectPinRead = DirectPinReadReg; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {portInputRegister(digitalPinToPort(pin)), digitalPinToBitMask(pin)}; +} + +// Special cases +#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) + +using DirectPinRead = DirectPinReadReg; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {portModeRegister(digitalPinToPort(pin)) + 8, + static_cast(digitalPinToBitMask(pin))}; +} + +// More special cases +#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) + +using DirectPinRead = DirectPinReadReg; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {portOutputRegister(pin), digitalPinToBitMask(pin)}; +} + +// Nordic +#elif defined(RBL_NRF51822) || defined(ARDUINO_ARCH_NRF52840) + +struct DirectPinRead { + uint32_t pin; + bool read() const { return nrf_gpio_pin_read(pin); } +}; +inline DirectPinRead direct_pin_read(pin_t pin) { +#if defined(RBL_NRF51822) + return {static_cast(pin)}; +#elif defined(ARDUINO_ARCH_NRF52840) + return {static_cast(digitalPinToPinName(pin))}; +#else +#error "Unknown Nordic board" +#endif +} + +// Raspberry Pi RP2040 +#elif defined(ARDUINO_ARCH_RP2040) + +#include +using DirectPinRead = DirectPinReadReg; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {&sio_hw->gpio_in, uint32_t(1) << pin}; +} + +// ARM mbed OS +#elif defined(ARDUINO_ARCH_MBED) + +#include +struct DirectPinRead { + mbed::DigitalIn pin; + bool read() const { return pin.read(); } +}; +inline DirectPinRead direct_pin_read(pin_t pin) { + return {mbed::DigitalIn {digitalPinToPinName(pin), PullUp}}; +} + +#else +#warning "Unknown board. Please define the direct_pin_read function." + +struct DirectPinRead { + uint8_t pin; + bool read() const { return ::digitalRead(pin) == HIGH; } +}; +inline DirectPinRead direct_pin_read(uint8_t pin) { return {pin}; } + +#endif + +END_CS_NAMESPACE \ No newline at end of file diff --git a/src/Submodules/Encoder/Encoder-AVR.ipp b/src/Submodules/Encoder/Encoder-AVR.ipp deleted file mode 100644 index 5897ea1828..0000000000 --- a/src/Submodules/Encoder/Encoder-AVR.ipp +++ /dev/null @@ -1,160 +0,0 @@ -inline void Encoder::update(Encoder_internal_state_t *arg) { - // The compiler believes this is just 1 line of code, so - // it will inline this function into each interrupt - // handler. That's a tiny bit faster, but grows the code. - // Especially when used with ENCODER_OPTIMIZE_INTERRUPTS, - // the inline nature allows the ISR prologue and epilogue - // to only save/restore necessary registers, for very nice - // speed increase. - asm volatile("ld r30, X+" - "\n\t" - "ld r31, X+" - "\n\t" - "ld r24, Z" - "\n\t" // r24 = pin1 input - "ld r30, X+" - "\n\t" - "ld r31, X+" - "\n\t" - "ld r25, Z" - "\n\t" // r25 = pin2 input - "ld r30, X+" - "\n\t" // r30 = pin1 mask - "ld r31, X+" - "\n\t" // r31 = pin2 mask - "ld r22, X" - "\n\t" // r22 = state - "andi r22, 3" - "\n\t" - "and r24, r30" - "\n\t" - "breq L%=1" - "\n\t" // if (pin1) - "ori r22, 4" - "\n\t" // state |= 4 - "L%=1:" - "and r25, r31" - "\n\t" - "breq L%=2" - "\n\t" // if (pin2) - "ori r22, 8" - "\n\t" // state |= 8 - "L%=2:" - "ldi r30, lo8(pm(L%=table))" - "\n\t" - "ldi r31, hi8(pm(L%=table))" - "\n\t" - "add r30, r22" - "\n\t" - "adc r31, __zero_reg__" - "\n\t" - "asr r22" - "\n\t" - "asr r22" - "\n\t" - "st X+, r22" - "\n\t" // store new state - "ld r22, X+" - "\n\t" - "ld r23, X+" - "\n\t" - "ld r24, X+" - "\n\t" - "ld r25, X+" - "\n\t" - "ijmp" - "\n\t" // jumps to update_finishup() - // TODO move this table to another static function, - // so it doesn't get needlessly duplicated. Easier - // said than done, due to linker issues and inlining - "L%=table:" - "\n\t" - "rjmp L%=end" - "\n\t" // 0 - "rjmp L%=plus1" - "\n\t" // 1 - "rjmp L%=minus1" - "\n\t" // 2 - "rjmp L%=plus2" - "\n\t" // 3 - "rjmp L%=minus1" - "\n\t" // 4 - "rjmp L%=end" - "\n\t" // 5 - "rjmp L%=minus2" - "\n\t" // 6 - "rjmp L%=plus1" - "\n\t" // 7 - "rjmp L%=plus1" - "\n\t" // 8 - "rjmp L%=minus2" - "\n\t" // 9 - "rjmp L%=end" - "\n\t" // 10 - "rjmp L%=minus1" - "\n\t" // 11 - "rjmp L%=plus2" - "\n\t" // 12 - "rjmp L%=minus1" - "\n\t" // 13 - "rjmp L%=plus1" - "\n\t" // 14 - "rjmp L%=end" - "\n\t" // 15 - "L%=minus2:" - "\n\t" - "subi r22, 2" - "\n\t" - "sbci r23, 0" - "\n\t" - "sbci r24, 0" - "\n\t" - "sbci r25, 0" - "\n\t" - "rjmp L%=store" - "\n\t" - "L%=minus1:" - "\n\t" - "subi r22, 1" - "\n\t" - "sbci r23, 0" - "\n\t" - "sbci r24, 0" - "\n\t" - "sbci r25, 0" - "\n\t" - "rjmp L%=store" - "\n\t" - "L%=plus2:" - "\n\t" - "subi r22, 254" - "\n\t" - "rjmp L%=z" - "\n\t" - "L%=plus1:" - "\n\t" - "subi r22, 255" - "\n\t" - "L%=z:" - "sbci r23, 255" - "\n\t" - "sbci r24, 255" - "\n\t" - "sbci r25, 255" - "\n\t" - "L%=store:" - "\n\t" - "st -X, r25" - "\n\t" - "st -X, r24" - "\n\t" - "st -X, r23" - "\n\t" - "st -X, r22" - "\n\t" - "L%=end:" - "\n" - : - : "x"(arg) - : "r22", "r23", "r24", "r25", "r30", "r31"); -} diff --git a/src/Submodules/Encoder/Encoder.cpp b/src/Submodules/Encoder/Encoder.cpp deleted file mode 100644 index df57ecfcf4..0000000000 --- a/src/Submodules/Encoder/Encoder.cpp +++ /dev/null @@ -1,118 +0,0 @@ -#ifdef ARDUINO - -#include "Encoder.h" - -BEGIN_CS_NAMESPACE - -#include "codegen/ISRs-def.ipp" - -Encoder::Encoder(uint8_t pin1, uint8_t pin2) : pin1(pin1), pin2(pin2) { - // It's much faster to use the GPIO registers directly, rather than - // calling digitalRead every time we need to read a pin. - // digitalRead looks up the register and bitmasks every time it's called - // but here, we look them up once in the constructor. - encoder.pin1_register = PIN_TO_BASEREG(pin1); - encoder.pin1_bitmask = PIN_TO_BITMASK(pin1); - encoder.pin2_register = PIN_TO_BASEREG(pin2); - encoder.pin2_bitmask = PIN_TO_BITMASK(pin2); - encoder.position = 0; -} - -Encoder::Encoder(Encoder &&other) { *this = enc_util::move(other); } - -Encoder &Encoder::operator=(Encoder &&other) { - // First swap the normal member variables: - enc_util::swap(this->pin1, other.pin1); - enc_util::swap(this->pin2, other.pin2); - enc_util::swap(this->interrupts_in_use, other.interrupts_in_use); - - // Next, update the pointers in interruptArgs: - // When interrupts are in use, there is a global interrupt context - // variable that holds a pointer to the encoders that are being swapped - // or moved. - // After moving, this pointer would no longer be valid, so it has to be - // changed to point to the new encoder object. - // Calling attachInterrupt is not necessary, because this should already - // have happened in the begin method if interrupts_in_use is nonzero. - // Before messing with the state variables that can be changed or - // accessed from within an ISR, we have to disable interrupts. - noInterrupts(); - enc_util::swap(this->encoder, other.encoder); - if (this->interrupts_in_use > 0) { - auto int1 = digitalPinToInterrupt(this->pin1); - if (int1 != NOT_AN_INTERRUPT) - interruptArgs[int1] = &this->encoder; - auto int2 = digitalPinToInterrupt(this->pin2); - if (int2 != NOT_AN_INTERRUPT) - interruptArgs[int2] = &this->encoder; - } - if (other.interrupts_in_use > 0) { - auto int1 = digitalPinToInterrupt(other.pin1); - if (int1 != NOT_AN_INTERRUPT) - interruptArgs[int1] = &other.encoder; - auto int2 = digitalPinToInterrupt(other.pin2); - if (int2 != NOT_AN_INTERRUPT) - interruptArgs[int2] = &other.encoder; - } - interrupts(); - - return *this; -} - -Encoder::~Encoder() { - // If interrupts are in use, there are dangling pointers to the encoder - // state in the global interrupt contexts. These have to be detached - // when the encoder object is removed. - end(); -} - -void Encoder::begin() { - pinMode(pin1, INPUT_PULLUP); - pinMode(pin2, INPUT_PULLUP); - // allow time for a passive R-C filter to charge - // through the pullup resistors, before reading - // the initial state - delayMicroseconds(2000); - uint8_t s = 0; - if (DIRECT_PIN_READ(encoder.pin1_register, encoder.pin1_bitmask)) - s |= 1; - if (DIRECT_PIN_READ(encoder.pin2_register, encoder.pin2_bitmask)) - s |= 2; - encoder.state = s; - - attachInterruptCtx(digitalPinToInterrupt(pin1)); - attachInterruptCtx(digitalPinToInterrupt(pin2)); - #ifdef ARDUINO_ARCH_MBED - pinMode(pin1, INPUT_PULLUP); - pinMode(pin2, INPUT_PULLUP); - #endif -} - -void Encoder::end() { - if (interrupts_in_use > 0) { - detachInterruptCtx(digitalPinToInterrupt(pin1)); - detachInterruptCtx(digitalPinToInterrupt(pin2)); - } -} - -void Encoder::attachInterruptCtx(int interrupt) { - if (interrupt != NOT_AN_INTERRUPT) { - interruptArgs[interrupt] = &encoder; - ++interrupts_in_use; - attachInterrupt(interrupt, EncoderISRs::getISR(interrupt), CHANGE); - } -} - -void Encoder::detachInterruptCtx(int interrupt) { - if (interrupt != NOT_AN_INTERRUPT) { - detachInterrupt(interrupt); - --interrupts_in_use; - interruptArgs[interrupt] = nullptr; - } -} - -Encoder_internal_state_t *Encoder::interruptArgs[CS_ENCODER_ARGLIST_SIZE] = {}; - -END_CS_NAMESPACE - -#endif \ No newline at end of file diff --git a/src/Submodules/Encoder/Encoder.h b/src/Submodules/Encoder/Encoder.h deleted file mode 100644 index ab1dd4040b..0000000000 --- a/src/Submodules/Encoder/Encoder.h +++ /dev/null @@ -1,134 +0,0 @@ -/* Encoder Library, for measuring quadrature encoded signals - * http://www.pjrc.com/teensy/td_libs_Encoder.html - * Copyright (c) 2011,2013 PJRC.COM, LLC - Paul Stoffregen - * - * April-September 2020 - Pieter P: - * make encoders moveable and add begin method for deterministic - * initialization, large cleanup - * Version 1.2 - fix -2 bug in C-only code - * Version 1.1 - expand to support boards with up to 60 interrupts - * Version 1.0 - initial release - * - * 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 "utility/direct_pin_read.h" -#include "utility/move.h" -#include "utility/interrupt_pins.h" - -BEGIN_CS_NAMESPACE - -// Use IRAM_ATTR for ISRs to prevent ESP8266 resets -#if defined(ESP8266) || defined(ESP32) -#define CS_ENCODER_ISR_ATTR IRAM_ATTR -#else -#define CS_ENCODER_ISR_ATTR -#endif - -#define CS_ENCODER_ARGLIST_SIZE CORE_NUM_INTERRUPT - -/// All the data needed by interrupts is consolidated into this ugly struct -/// to facilitate assembly language optimizing of the speed critical update. -/// The assembly code uses auto-incrementing addressing modes, so the struct -/// must remain in exactly this order. -struct Encoder_internal_state_t { - volatile IO_REG_TYPE *pin1_register; - volatile IO_REG_TYPE *pin2_register; - IO_REG_TYPE pin1_bitmask; - IO_REG_TYPE pin2_bitmask; - uint8_t state; - int32_t position; -}; - -/// Class for reading quadrature encoders, based on -/// http://www.pjrc.com/teensy/td_libs_Encoder.html -class Encoder { - public: - /** - * @brief Constructor. - * - * @param pin1 - * The first pin, connected to the encoder's "A" pin. - * @param pin2 - * The second pin, connected to the encoder's "B" pin. - * - * The internal pull-up resistors will be enabled on these pins upon - * initialization (when calling the `begin` method). - */ - Encoder(uint8_t pin1, uint8_t pin2); - - /// Copy constructor: copying an Encoder object is semantically meaningless, - /// so it has been deleted. - Encoder(const Encoder &) = delete; - /// Copy assignment: copying an Encoder object is semantically meaningless, - /// so it has been deleted. - Encoder &operator=(const Encoder &) = delete; - - /// Move constructor. - Encoder(Encoder &&other); - /// Move assignment. - Encoder &operator=(Encoder &&other); - - /// Destructor. - ~Encoder(); - - /// Initialize this encoder by enabling the pull-up resistors and attaching - /// the interrupts handlers (if interrupts are enabled and available on the - /// the given pins). - void begin(); - /// Disable the interrupts used by this encoder. - void end(); - - public: - /// Read the current absolute position of the encoder. - int32_t read(); - /// Read the current absolute position of the encoder and reset it to zero - /// afterwards. - int32_t readAndReset(); - /// Set the absolute position to the given value. - void write(int32_t p); - - private: - void attachInterruptCtx(int interrupt); - void detachInterruptCtx(int interrupt); - - private: - Encoder_internal_state_t encoder; - uint8_t pin1, pin2; - uint8_t interrupts_in_use = 0; - - - public: - /// `update()` is not meant to be called from outside Encoder, - /// but it is public to allow static interrupt routines. - /// DO NOT call update() directly from sketches. - CS_ENCODER_ISR_ATTR static void update(Encoder_internal_state_t *arg); - /// Similarly to `update()`, don't use these interrupt handler arguments - /// from your sketch. - static Encoder_internal_state_t *interruptArgs[CS_ENCODER_ARGLIST_SIZE]; -}; - -END_CS_NAMESPACE - -#include "Encoder.ipp" diff --git a/src/Submodules/Encoder/NumInterrupts.hpp b/src/Submodules/Encoder/NumInterrupts.hpp new file mode 100644 index 0000000000..7823db9154 --- /dev/null +++ b/src/Submodules/Encoder/NumInterrupts.hpp @@ -0,0 +1,100 @@ +#pragma once + +#include +#include + +#ifdef ARDUINO_ARCH_NRF52840 +#include +#endif + +BEGIN_CS_NAMESPACE + +// Teensy (and maybe others) +#if defined(CORE_NUM_INTERRUPT) +// CORE_NUM_INTERRUPT already defined by core + +// Wiring boards +#elif defined(WIRING) +#define CORE_NUM_INTERRUPT NUM_EXTERNAL_INTERRUPTS + +// Arduino Uno, Duemilanove, Diecimila, LilyPad, Mini, Fio, etc... +#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || \ + defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) +#define CORE_NUM_INTERRUPT 2 + +// Arduino Mega +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) +#define CORE_NUM_INTERRUPT 6 + +// Arduino Nano Every, Uno R2 Wifi +#elif defined(__AVR_ATmega4809__) +#define CORE_NUM_INTERRUPT 22 + +// Arduino Leonardo +#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY) +#define CORE_NUM_INTERRUPT 5 + +// Sanguino (untested) and ATmega1284P +#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) || \ + defined(__AVR_ATmega1284P__) +#define CORE_NUM_INTERRUPT 3 + +// ATmega32u2 and ATmega32u16 based boards with HoodLoader2 +#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) +#define CORE_NUM_INTERRUPT 8 + +#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) +#define CORE_NUM_INTERRUPT 1 + +// https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x313.md +#elif defined(__AVR_ATtinyX313__) +#define CORE_NUM_INTERRUPT 2 + +// Attiny167 same core as above +#elif defined(__AVR_ATtiny167__) +#define CORE_NUM_INTERRUPT 2 + +// Arduino Due +#elif defined(__SAM3X8E__) +#define CORE_NUM_INTERRUPT 54 + +// ESP8266 (https://github.com/esp8266/Arduino/) +#elif defined(ESP8266) +#define CORE_NUM_INTERRUPT EXTERNAL_NUM_INTERRUPTS + +// ESP32 (https://github.com/espressif/arduino-esp32) +#elif defined(ESP32) +#define CORE_NUM_INTERRUPT 40 + +// Arduino Zero - TODO: interrupts do not seem to work +// please help, contribute a fix! +#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) +#define CORE_NUM_INTERRUPT 31 + +// SAMD51 +#elif defined(__SAMD51__) +#define CORE_NUM_INTERRUPT 26 + +// Arduino Nano BLE +#elif defined(ARDUINO_ARCH_NRF52840) +#define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS + +// Arduino Nano RP2040 Connect +#elif defined(ARDUINO_NANO_RP2040_CONNECT) +#define CORE_NUM_INTERRUPT 20 + +#elif defined(ARDUINO_ARCH_RP2040) +#define CORE_NUM_INTERRUPT 26 + +// ARM mbed OS +#elif defined(ARDUINO_ARCH_MBED) +#define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS + +// Others +#else +#warning "Unknown board. Please specify the number of external interrupts." +#define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS + +#endif + +END_CS_NAMESPACE diff --git a/src/Submodules/Encoder/README.md b/src/Submodules/Encoder/README.md index 7f52ea95f6..adec9991c8 100644 --- a/src/Submodules/Encoder/README.md +++ b/src/Submodules/Encoder/README.md @@ -1,9 +1,9 @@ # Encoder Library -This library is a fork of PJRC's popular Encoder library -(http://www.pjrc.com/teensy/td_libs_Encoder.html). +This library is an adapted and modernized version of PJRC's popular Encoder +library (http://www.pjrc.com/teensy/td_libs_Encoder.html). -I applied the following changes: +It includes following changes: - Delete the copy constructor and copy assignment operator: in the original library, the default copy constructor doesn't work, and leaves dangling pointers to the interrupt contexts when used accidentally. diff --git a/src/Submodules/Encoder/codegen/ISRs-def.ipp b/src/Submodules/Encoder/codegen/ISRs-def.ipp index b108b24781..fbb4c8e90f 100644 --- a/src/Submodules/Encoder/codegen/ISRs-def.ipp +++ b/src/Submodules/Encoder/codegen/ISRs-def.ipp @@ -5,195 +5,198 @@ // // // ========================================================================== // -// Edit and re-run ISRs.py instead +// Edit and re-run ISRs.py instead namespace EncoderISRs { -using ISR_fun_t = void (*)(void); +using ISR_fun_t = void (*)(); -static ISR_fun_t getISR(uint8_t interrupt) { +[[maybe_unused]] static ISR_fun_t getISR(int interrupt) { switch (interrupt) { #if 0 < CS_ENCODER_ARGLIST_SIZE - case 0: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[0]); }; + case 0: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[0]->update(); }; #endif #if 1 < CS_ENCODER_ARGLIST_SIZE - case 1: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[1]); }; + case 1: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[1]->update(); }; #endif #if 2 < CS_ENCODER_ARGLIST_SIZE - case 2: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[2]); }; + case 2: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[2]->update(); }; #endif #if 3 < CS_ENCODER_ARGLIST_SIZE - case 3: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[3]); }; + case 3: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[3]->update(); }; #endif #if 4 < CS_ENCODER_ARGLIST_SIZE - case 4: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[4]); }; + case 4: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[4]->update(); }; #endif #if 5 < CS_ENCODER_ARGLIST_SIZE - case 5: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[5]); }; + case 5: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[5]->update(); }; #endif #if 6 < CS_ENCODER_ARGLIST_SIZE - case 6: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[6]); }; + case 6: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[6]->update(); }; #endif #if 7 < CS_ENCODER_ARGLIST_SIZE - case 7: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[7]); }; + case 7: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[7]->update(); }; #endif #if 8 < CS_ENCODER_ARGLIST_SIZE - case 8: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[8]); }; + case 8: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[8]->update(); }; #endif #if 9 < CS_ENCODER_ARGLIST_SIZE - case 9: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[9]); }; + case 9: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[9]->update(); }; #endif #if 10 < CS_ENCODER_ARGLIST_SIZE - case 10: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[10]); }; + case 10: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[10]->update(); }; #endif #if 11 < CS_ENCODER_ARGLIST_SIZE - case 11: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[11]); }; + case 11: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[11]->update(); }; #endif #if 12 < CS_ENCODER_ARGLIST_SIZE - case 12: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[12]); }; + case 12: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[12]->update(); }; #endif #if 13 < CS_ENCODER_ARGLIST_SIZE - case 13: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[13]); }; + case 13: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[13]->update(); }; #endif #if 14 < CS_ENCODER_ARGLIST_SIZE - case 14: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[14]); }; + case 14: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[14]->update(); }; #endif #if 15 < CS_ENCODER_ARGLIST_SIZE - case 15: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[15]); }; + case 15: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[15]->update(); }; #endif #if 16 < CS_ENCODER_ARGLIST_SIZE - case 16: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[16]); }; + case 16: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[16]->update(); }; #endif #if 17 < CS_ENCODER_ARGLIST_SIZE - case 17: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[17]); }; + case 17: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[17]->update(); }; #endif #if 18 < CS_ENCODER_ARGLIST_SIZE - case 18: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[18]); }; + case 18: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[18]->update(); }; #endif #if 19 < CS_ENCODER_ARGLIST_SIZE - case 19: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[19]); }; + case 19: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[19]->update(); }; #endif #if 20 < CS_ENCODER_ARGLIST_SIZE - case 20: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[20]); }; + case 20: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[20]->update(); }; #endif #if 21 < CS_ENCODER_ARGLIST_SIZE - case 21: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[21]); }; + case 21: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[21]->update(); }; #endif #if 22 < CS_ENCODER_ARGLIST_SIZE - case 22: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[22]); }; + case 22: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[22]->update(); }; #endif #if 23 < CS_ENCODER_ARGLIST_SIZE - case 23: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[23]); }; + case 23: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[23]->update(); }; #endif #if 24 < CS_ENCODER_ARGLIST_SIZE - case 24: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[24]); }; + case 24: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[24]->update(); }; #endif #if 25 < CS_ENCODER_ARGLIST_SIZE - case 25: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[25]); }; + case 25: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[25]->update(); }; #endif #if 26 < CS_ENCODER_ARGLIST_SIZE - case 26: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[26]); }; + case 26: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[26]->update(); }; #endif #if 27 < CS_ENCODER_ARGLIST_SIZE - case 27: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[27]); }; + case 27: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[27]->update(); }; #endif #if 28 < CS_ENCODER_ARGLIST_SIZE - case 28: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[28]); }; + case 28: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[28]->update(); }; #endif #if 29 < CS_ENCODER_ARGLIST_SIZE - case 29: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[29]); }; + case 29: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[29]->update(); }; #endif #if 30 < CS_ENCODER_ARGLIST_SIZE - case 30: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[30]); }; + case 30: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[30]->update(); }; #endif #if 31 < CS_ENCODER_ARGLIST_SIZE - case 31: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[31]); }; + case 31: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[31]->update(); }; #endif #if 32 < CS_ENCODER_ARGLIST_SIZE - case 32: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[32]); }; + case 32: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[32]->update(); }; #endif #if 33 < CS_ENCODER_ARGLIST_SIZE - case 33: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[33]); }; + case 33: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[33]->update(); }; #endif #if 34 < CS_ENCODER_ARGLIST_SIZE - case 34: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[34]); }; + case 34: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[34]->update(); }; #endif #if 35 < CS_ENCODER_ARGLIST_SIZE - case 35: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[35]); }; + case 35: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[35]->update(); }; #endif #if 36 < CS_ENCODER_ARGLIST_SIZE - case 36: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[36]); }; + case 36: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[36]->update(); }; #endif #if 37 < CS_ENCODER_ARGLIST_SIZE - case 37: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[37]); }; + case 37: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[37]->update(); }; #endif #if 38 < CS_ENCODER_ARGLIST_SIZE - case 38: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[38]); }; + case 38: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[38]->update(); }; #endif #if 39 < CS_ENCODER_ARGLIST_SIZE - case 39: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[39]); }; + case 39: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[39]->update(); }; #endif #if 40 < CS_ENCODER_ARGLIST_SIZE - case 40: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[40]); }; + case 40: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[40]->update(); }; #endif #if 41 < CS_ENCODER_ARGLIST_SIZE - case 41: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[41]); }; + case 41: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[41]->update(); }; #endif #if 42 < CS_ENCODER_ARGLIST_SIZE - case 42: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[42]); }; + case 42: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[42]->update(); }; #endif #if 43 < CS_ENCODER_ARGLIST_SIZE - case 43: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[43]); }; + case 43: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[43]->update(); }; #endif #if 44 < CS_ENCODER_ARGLIST_SIZE - case 44: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[44]); }; + case 44: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[44]->update(); }; #endif #if 45 < CS_ENCODER_ARGLIST_SIZE - case 45: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[45]); }; + case 45: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[45]->update(); }; #endif #if 46 < CS_ENCODER_ARGLIST_SIZE - case 46: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[46]); }; + case 46: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[46]->update(); }; #endif #if 47 < CS_ENCODER_ARGLIST_SIZE - case 47: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[47]); }; + case 47: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[47]->update(); }; #endif #if 48 < CS_ENCODER_ARGLIST_SIZE - case 48: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[48]); }; + case 48: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[48]->update(); }; #endif #if 49 < CS_ENCODER_ARGLIST_SIZE - case 49: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[49]); }; + case 49: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[49]->update(); }; #endif #if 50 < CS_ENCODER_ARGLIST_SIZE - case 50: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[50]); }; + case 50: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[50]->update(); }; #endif #if 51 < CS_ENCODER_ARGLIST_SIZE - case 51: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[51]); }; + case 51: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[51]->update(); }; #endif #if 52 < CS_ENCODER_ARGLIST_SIZE - case 52: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[52]); }; + case 52: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[52]->update(); }; #endif #if 53 < CS_ENCODER_ARGLIST_SIZE - case 53: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[53]); }; + case 53: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[53]->update(); }; #endif #if 54 < CS_ENCODER_ARGLIST_SIZE - case 54: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[54]); }; + case 54: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[54]->update(); }; #endif #if 55 < CS_ENCODER_ARGLIST_SIZE - case 55: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[55]); }; + case 55: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[55]->update(); }; #endif #if 56 < CS_ENCODER_ARGLIST_SIZE - case 56: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[56]); }; + case 56: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[56]->update(); }; #endif #if 57 < CS_ENCODER_ARGLIST_SIZE - case 57: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[57]); }; + case 57: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[57]->update(); }; #endif #if 58 < CS_ENCODER_ARGLIST_SIZE - case 58: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[58]); }; + case 58: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[58]->update(); }; #endif #if 59 < CS_ENCODER_ARGLIST_SIZE - case 59: return +[]() CS_ENCODER_ISR_ATTR { Encoder::update(Encoder::interruptArgs[59]); }; + case 59: return +[]() CS_ENCODER_ISR_ATTR { AHEncoder::interruptArgs[59]->update(); }; #endif default: return nullptr; + static_assert(CS_ENCODER_ARGLIST_SIZE <= 60, + "Error: more external interrupts than expected. " + "Increase ISRs.py:max_num_interrupts and try again."); } }; diff --git a/src/Submodules/Encoder/codegen/ISRs.py b/src/Submodules/Encoder/codegen/ISRs.py index 6666ed9487..8dc844ee7a 100644 --- a/src/Submodules/Encoder/codegen/ISRs.py +++ b/src/Submodules/Encoder/codegen/ISRs.py @@ -12,11 +12,11 @@ // // // ========================================================================== // -// Edit and re-run {basename(__file__)} instead +// Edit and re-run {basename(__file__)} instead namespace EncoderISRs {{ -using ISR_fun_t = void (*)(void); +using ISR_fun_t = void (*)(); """ @@ -25,16 +25,19 @@ """ -ISRs = """static ISR_fun_t getISR(uint8_t interrupt) { +ISRs = """[[maybe_unused]] static ISR_fun_t getISR(int interrupt) { switch (interrupt) { """ for i in range(max_num_interrupts): ISRs += f' #if {i} < CS_ENCODER_ARGLIST_SIZE\n' - ISRs += f' case {i}: return +[]() CS_ENCODER_ISR_ATTR {{ Encoder::update(Encoder::interruptArgs[{i}]); }};\n' + ISRs += f' case {i}: return +[]() CS_ENCODER_ISR_ATTR {{ AHEncoder::interruptArgs[{i}]->update(); }};\n' ISRs += f' #endif\n' -ISRs += """ default: return nullptr; - } -}; +ISRs += f""" default: return nullptr; + static_assert(CS_ENCODER_ARGLIST_SIZE <= {max_num_interrupts}, + "Error: more external interrupts than expected. " + "Increase {basename(__file__)}:max_num_interrupts and try again."); + }} +}}; """ with open(join(dirname(__file__), 'ISRs-def.ipp'), 'w') as f: diff --git a/src/Submodules/Encoder/utility/direct_pin_read.h b/src/Submodules/Encoder/utility/direct_pin_read.h deleted file mode 100644 index 86703f87a0..0000000000 --- a/src/Submodules/Encoder/utility/direct_pin_read.h +++ /dev/null @@ -1,127 +0,0 @@ -#ifndef direct_pin_read_h_ -#define direct_pin_read_h_ - -#if defined(__AVR__) - -#define IO_REG_TYPE uint8_t -#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(TEENSYDUINO) && (defined(KINETISK) || defined(KINETISL)) - -#define IO_REG_TYPE uint8_t -#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(__IMXRT1052__) || defined(__IMXRT1062__) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (portOutputRegister(pin)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(__SAM3X8E__) // || defined(ESP8266) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(__PIC32MX__) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (portModeRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base+4)) & (mask)) ? 1 : 0) - -/* ESP8266 v2.0.0 Arduino workaround for bug https://github.com/esp8266/Arduino/issues/1110 */ -#elif defined(ESP8266) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)(0x60000000+(0x318))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -/* ESP32 Arduino (https://github.com/espressif/arduino-esp32) */ -#elif defined(ESP32) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (portInputRegister(digitalPinToPort(pin))) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*((base)+8)) & (mask)) ? 1 : 0) - -#elif defined(__SAMD51__) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) portInputRegister(digitalPinToPort(pin)) -#define PIN_TO_BITMASK(pin) (digitalPinToBitMask(pin)) -#define DIRECT_PIN_READ(base, mask) (((*(base)) & (mask)) ? 1 : 0) - -#elif defined(RBL_NRF51822) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (0) -#define PIN_TO_BITMASK(pin) (pin) -#define DIRECT_PIN_READ(base, pin) nrf_gpio_pin_read(pin) - -#elif defined(ARDUINO_ARCH_NRF52840) - -#define IO_REG_TYPE uint32_t -#define PIN_TO_BASEREG(pin) (0) -#define PIN_TO_BITMASK(pin) digitalPinToPinName(pin) -#define DIRECT_PIN_READ(base, pin) nrf_gpio_pin_read(pin) - -#elif defined(ARDUINO_ARCH_RP2040) - -#define IO_REG_TYPE uint -#define PIN_TO_BASEREG(pin) (0) -#define PIN_TO_BITMASK(pin) pin -#define DIRECT_PIN_READ(base, pin) gpio_get(pin) - -#elif defined(ARDUINO_ARCH_MBED) - -#include -#include -#define IO_REG_TYPE std::unique_ptr -#define PIN_TO_BASEREG(pin) (nullptr) -#define PIN_TO_BITMASK(pin) std::make_unique(digitalPinToPinName(pin), PullUp) -#define DIRECT_PIN_READ(base, pin) (pin)->read() - -#elif defined(__arc__) /* Arduino101/Genuino101 specifics */ - -#include "scss_registers.h" -#include "portable.h" -#include "avr/pgmspace.h" -#define GPIO_ID(pin) (g_APinDescription[pin].ulGPIOId) -#define GPIO_TYPE(pin) (g_APinDescription[pin].ulGPIOType) -#define GPIO_BASE(pin) (g_APinDescription[pin].ulGPIOBase) -#define EXT_PORT_OFFSET_SS 0x0A -#define EXT_PORT_OFFSET_SOC 0x50 -#define PIN_TO_BASEREG(pin) ((volatile uint32_t *)g_APinDescription[pin].ulGPIOBase) -#define PIN_TO_BITMASK(pin) pin -#define IO_REG_TYPE uint32_t -static inline __attribute__((always_inline)) -IO_REG_TYPE directRead(volatile IO_REG_TYPE *base, IO_REG_TYPE pin) -{ - IO_REG_TYPE ret; - if (SS_GPIO == GPIO_TYPE(pin)) { - ret = READ_ARC_REG(((IO_REG_TYPE)base + EXT_PORT_OFFSET_SS)); - } else { - ret = MMIO_REG_VAL_FROM_BASE((IO_REG_TYPE)base, EXT_PORT_OFFSET_SOC); - } - return ((ret >> GPIO_ID(pin)) & 0x01); -} -#define DIRECT_PIN_READ(base, pin) directRead(base, pin) - -#endif - -#endif diff --git a/src/Submodules/Encoder/utility/interrupt_pins.h b/src/Submodules/Encoder/utility/interrupt_pins.h deleted file mode 100644 index 43766ce22c..0000000000 --- a/src/Submodules/Encoder/utility/interrupt_pins.h +++ /dev/null @@ -1,358 +0,0 @@ -// interrupt pins for known boards -#include -#ifdef ARDUINO_ARCH_NRF52840 -#include -#endif - -// Teensy (and maybe others) define these automatically -#if !defined(CORE_NUM_INTERRUPT) - -// Wiring boards -#if defined(WIRING) - #define CORE_NUM_INTERRUPT NUM_EXTERNAL_INTERRUPTS - #if NUM_EXTERNAL_INTERRUPTS > 0 - #define CORE_INT0_PIN EI0 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 1 - #define CORE_INT1_PIN EI1 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 2 - #define CORE_INT2_PIN EI2 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 3 - #define CORE_INT3_PIN EI3 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 4 - #define CORE_INT4_PIN EI4 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 5 - #define CORE_INT5_PIN EI5 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 6 - #define CORE_INT6_PIN EI6 - #endif - #if NUM_EXTERNAL_INTERRUPTS > 7 - #define CORE_INT7_PIN EI7 - #endif - -// Arduino Uno, Duemilanove, Diecimila, LilyPad, Mini, Fio, etc... -#elif defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) ||defined(__AVR_ATmega168__) || defined(__AVR_ATmega8__) - #define CORE_NUM_INTERRUPT 2 - #define CORE_INT0_PIN 2 - #define CORE_INT1_PIN 3 - -// Arduino Mega -#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) - #define CORE_NUM_INTERRUPT 6 - #define CORE_INT0_PIN 2 - #define CORE_INT1_PIN 3 - #define CORE_INT2_PIN 21 - #define CORE_INT3_PIN 20 - #define CORE_INT4_PIN 19 - #define CORE_INT5_PIN 18 - -// Arduino Nano Every, Uno R2 Wifi -#elif defined(__AVR_ATmega4809__) - #define CORE_NUM_INTERRUPT 22 - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - #define CORE_INT6_PIN 6 - #define CORE_INT7_PIN 7 - #define CORE_INT8_PIN 8 - #define CORE_INT9_PIN 9 - #define CORE_INT10_PIN 10 - #define CORE_INT11_PIN 11 - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - #define CORE_INT16_PIN 16 - #define CORE_INT17_PIN 17 - #define CORE_INT18_PIN 18 - #define CORE_INT19_PIN 19 - #define CORE_INT20_PIN 20 - #define CORE_INT21_PIN 21 - -// Arduino Leonardo (untested) -#elif defined(__AVR_ATmega32U4__) && !defined(CORE_TEENSY) - #define CORE_NUM_INTERRUPT 5 - #define CORE_INT0_PIN 3 - #define CORE_INT1_PIN 2 - #define CORE_INT2_PIN 0 - #define CORE_INT3_PIN 1 - #define CORE_INT4_PIN 7 - -// Sanguino (untested) and ATmega1284P -#elif defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega1284P__) - #define CORE_NUM_INTERRUPT 3 - #define CORE_INT0_PIN 10 - #define CORE_INT1_PIN 11 - #define CORE_INT2_PIN 2 - -// ATmega32u2 and ATmega32u16 based boards with HoodLoader2 -#elif defined(__AVR_ATmega32U2__) || defined(__AVR_ATmega16U2__) - #define CORE_NUM_INTERRUPT 8 - #define CORE_INT0_PIN 8 - #define CORE_INT1_PIN 17 - #define CORE_INT2_PIN 13 - #define CORE_INT3_PIN 14 - #define CORE_INT4_PIN 15 - #define CORE_INT5_PIN 16 - #define CORE_INT6_PIN 19 - #define CORE_INT7_PIN 20 - -// Chipkit Uno32 - attachInterrupt may not support CHANGE option -#elif defined(__PIC32MX__) && defined(_BOARD_UNO_) - #define CORE_NUM_INTERRUPT 5 - #define CORE_INT0_PIN 38 - #define CORE_INT1_PIN 2 - #define CORE_INT2_PIN 7 - #define CORE_INT3_PIN 8 - #define CORE_INT4_PIN 35 - -// Chipkit Uno32 - attachInterrupt may not support CHANGE option -#elif defined(__PIC32MX__) && defined(_BOARD_MEGA_) - #define CORE_NUM_INTERRUPT 5 - #define CORE_INT0_PIN 3 - #define CORE_INT1_PIN 2 - #define CORE_INT2_PIN 7 - #define CORE_INT3_PIN 21 - #define CORE_INT4_PIN 20 - -// http://hlt.media.mit.edu/?p=1229 -#elif defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) - #define CORE_NUM_INTERRUPT 1 - #define CORE_INT0_PIN 2 - -// ATtiny441 ATtiny841 -#elif defined(__AVR_ATtiny441__) || defined(__AVR_ATtiny841__) - #define CORE_NUM_INTERRUPT 1 - #define CORE_INT0_PIN 9 - -//https://github.com/SpenceKonde/ATTinyCore/blob/master/avr/extras/ATtiny_x313.md -#elif defined(__AVR_ATtinyX313__) - #define CORE_NUM_INTERRUPT 2 - #define CORE_INT0_PIN 4 - #define CORE_INT1_PIN 5 - -// Attiny167 same core as abobe -#elif defined(__AVR_ATtiny167__) - #define CORE_NUM_INTERRUPT 2 - #define CORE_INT0_PIN 14 - #define CORE_INT1_PIN 3 - - -// Arduino Due -#elif defined(__SAM3X8E__) - #define CORE_NUM_INTERRUPT 54 - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - #define CORE_INT6_PIN 6 - #define CORE_INT7_PIN 7 - #define CORE_INT8_PIN 8 - #define CORE_INT9_PIN 9 - #define CORE_INT10_PIN 10 - #define CORE_INT11_PIN 11 - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - #define CORE_INT16_PIN 16 - #define CORE_INT17_PIN 17 - #define CORE_INT18_PIN 18 - #define CORE_INT19_PIN 19 - #define CORE_INT20_PIN 20 - #define CORE_INT21_PIN 21 - #define CORE_INT22_PIN 22 - #define CORE_INT23_PIN 23 - #define CORE_INT24_PIN 24 - #define CORE_INT25_PIN 25 - #define CORE_INT26_PIN 26 - #define CORE_INT27_PIN 27 - #define CORE_INT28_PIN 28 - #define CORE_INT29_PIN 29 - #define CORE_INT30_PIN 30 - #define CORE_INT31_PIN 31 - #define CORE_INT32_PIN 32 - #define CORE_INT33_PIN 33 - #define CORE_INT34_PIN 34 - #define CORE_INT35_PIN 35 - #define CORE_INT36_PIN 36 - #define CORE_INT37_PIN 37 - #define CORE_INT38_PIN 38 - #define CORE_INT39_PIN 39 - #define CORE_INT40_PIN 40 - #define CORE_INT41_PIN 41 - #define CORE_INT42_PIN 42 - #define CORE_INT43_PIN 43 - #define CORE_INT44_PIN 44 - #define CORE_INT45_PIN 45 - #define CORE_INT46_PIN 46 - #define CORE_INT47_PIN 47 - #define CORE_INT48_PIN 48 - #define CORE_INT49_PIN 49 - #define CORE_INT50_PIN 50 - #define CORE_INT51_PIN 51 - #define CORE_INT52_PIN 52 - #define CORE_INT53_PIN 53 - -// ESP8266 (https://github.com/esp8266/Arduino/) -#elif defined(ESP8266) - #define CORE_NUM_INTERRUPT EXTERNAL_NUM_INTERRUPTS - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - // GPIO6-GPIO11 are typically used to interface with the flash memory IC on - // most esp8266 modules, so we should avoid adding interrupts to these pins. - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - -// ESP32 (https://github.com/espressif/arduino-esp32) -#elif defined(ESP32) - - #define CORE_NUM_INTERRUPT 40 - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - // GPIO6-GPIO11 are typically used to interface with the flash memory IC on - // esp32, so we should avoid adding interrupts to these pins. - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - #define CORE_INT16_PIN 16 - #define CORE_INT17_PIN 17 - #define CORE_INT18_PIN 18 - #define CORE_INT19_PIN 19 - #define CORE_INT21_PIN 21 - #define CORE_INT22_PIN 22 - #define CORE_INT23_PIN 23 - #define CORE_INT25_PIN 25 - #define CORE_INT26_PIN 26 - #define CORE_INT27_PIN 27 - #define CORE_INT32_PIN 32 - #define CORE_INT33_PIN 33 - #define CORE_INT34_PIN 34 - #define CORE_INT35_PIN 35 - #define CORE_INT36_PIN 36 - #define CORE_INT39_PIN 39 - - -// Arduino Zero - TODO: interrupts do not seem to work -// please help, contribute a fix! -#elif defined(__SAMD21G18A__) || defined(__SAMD21E18A__) - #define CORE_NUM_INTERRUPT 31 - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - #define CORE_INT6_PIN 6 - #define CORE_INT7_PIN 7 - #define CORE_INT8_PIN 8 - #define CORE_INT9_PIN 9 - #define CORE_INT10_PIN 10 - #define CORE_INT11_PIN 11 - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - #define CORE_INT16_PIN 16 - #define CORE_INT17_PIN 17 - #define CORE_INT18_PIN 18 - #define CORE_INT19_PIN 19 - #define CORE_INT20_PIN 20 - #define CORE_INT21_PIN 21 - #define CORE_INT22_PIN 22 - #define CORE_INT23_PIN 23 - #define CORE_INT24_PIN 24 - #define CORE_INT25_PIN 25 - #define CORE_INT26_PIN 26 - #define CORE_INT27_PIN 27 - #define CORE_INT28_PIN 28 - #define CORE_INT29_PIN 29 - #define CORE_INT30_PIN 30 - -#elif defined(__SAMD51__) - #define CORE_NUM_INTERRUPT 26 - #define CORE_INT0_PIN 0 - #define CORE_INT1_PIN 1 - #define CORE_INT2_PIN 2 - #define CORE_INT3_PIN 3 - #define CORE_INT4_PIN 4 - #define CORE_INT5_PIN 5 - #define CORE_INT6_PIN 6 - #define CORE_INT7_PIN 7 - #define CORE_INT8_PIN 8 - #define CORE_INT9_PIN 9 - #define CORE_INT10_PIN 10 - #define CORE_INT11_PIN 11 - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - #define CORE_INT14_PIN 14 - #define CORE_INT15_PIN 15 - #define CORE_INT16_PIN 16 - #define CORE_INT17_PIN 17 - #define CORE_INT18_PIN 18 - #define CORE_INT19_PIN 19 - #define CORE_INT20_PIN 20 - #define CORE_INT21_PIN 21 - #define CORE_INT22_PIN 22 - #define CORE_INT23_PIN 23 - #define CORE_INT24_PIN 24 - #define CORE_INT25_PIN 25 - -// Arduino 101 -#elif defined(__arc__) - #define CORE_NUM_INTERRUPT 14 - #define CORE_INT2_PIN 2 - #define CORE_INT5_PIN 5 - #define CORE_INT7_PIN 7 - #define CORE_INT8_PIN 8 - #define CORE_INT10_PIN 10 - #define CORE_INT11_PIN 11 - #define CORE_INT12_PIN 12 - #define CORE_INT13_PIN 13 - -// Arduino Nano BLE -#elif defined(ARDUINO_ARCH_NRF52840) - #define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS - -// Arduino Nano RP2040 Connect -#elif defined(ARDUINO_NANO_RP2040_CONNECT) - #define CORE_NUM_INTERRUPT 20 - -#elif defined(ARDUINO_ARCH_RP2040) - #define CORE_NUM_INTERRUPT 26 - -// mbedOS -#elif defined(ARDUINO_ARCH_MBED) - #define CORE_NUM_INTERRUPT NUM_DIGITAL_PINS - -#endif -#endif - -#if !defined(CORE_NUM_INTERRUPT) -#error "Interrupts are unknown for this board, please add to this code" -#endif -#if CORE_NUM_INTERRUPT <= 0 -#error "Encoder requires interrupt pins, but this board does not have any :(" -#error "You could try defining ENCODER_DO_NOT_USE_INTERRUPTS as a kludge." -#endif diff --git a/src/Submodules/Encoder/utility/move.h b/src/Submodules/Encoder/utility/move.h deleted file mode 100644 index df82b937cf..0000000000 --- a/src/Submodules/Encoder/utility/move.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - - -#include - -BEGIN_CS_NAMESPACE - -namespace enc_util { - -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; -template struct remove_reference { typedef T type; }; - -template -typename remove_reference::type && -move(T &&t) { - return static_cast::type &&>(t); -} - -template -void swap(T &t1, T &t2) { - T temp = move(t1); - t1 = move(t2); - t2 = move(temp); -} - -} // namespace enc_util - -END_CS_NAMESPACE