Control Surface main
MIDI Control Surface library for Arduino
Loading...
Searching...
No Matches
AHEncoder.cpp
Go to the documentation of this file.
1#ifdef ARDUINO
2
3#include "AHEncoder.hpp"
4
5#include <AH/STL/utility> // std::swap
6
8
9#ifndef CS_CUSTOM_INTERRUPT_TO_INDEX
12#endif
13
15 : pins {pinA, pinB},
16 direct_pins {direct_pin_read(pinA), direct_pin_read(pinB)} {
17 // It's much faster to use the GPIO registers directly, rather than
18 // calling digitalRead every time we need to read a pin.
19 // digitalRead looks up the register and bitmasks every time it's called
20 // but here, we look them up once in the constructor.
21}
22
24 : pins (other.pins), direct_pins (std::move(other.direct_pins)) {
25 if (other.interrupts_in_use)
26 FATAL_ERROR(F("Cannot move from initialized AHEncoder."), 0x9311);
27}
28
30 swap(*this, other);
31 return *this;
32}
33
35 // First swap the normal member variables:
36 std::swap(a.interrupts_in_use, b.interrupts_in_use);
37 std::swap(a.pins, b.pins);
38
39 // Next, update the pointers in instance_table:
40 // When interrupts are in use, there is a global interrupt context
41 // variable that holds a pointer to the encoders that are being swapped
42 // or moved.
43 // After moving, this pointer would no longer be valid, so it has to be
44 // changed to point to the new encoder object.
45 // Calling attachInterrupt is not necessary, because this should already
46 // have happened in the begin method if interrupts_in_use is nonzero.
47 // Before messing with the state variables that can be changed or
48 // accessed from within an ISR, we have to disable interrupts.
50 std::swap(a.state, b.state);
51 std::swap(a.direct_pins, b.direct_pins);
52 std::swap(a.position, b.position);
53 if (a.interrupts_in_use > 0) {
54 int int1 = digitalPinToInterrupt(a.pins[0]);
57 int int2 = digitalPinToInterrupt(a.pins[1]);
60 }
61 if (b.interrupts_in_use > 0) {
68 }
69 interrupts();
70}
71
73 // If interrupts are in use, there are dangling pointers to the encoder
74 // state in the global interrupt contexts. These have to be detached
75 // when the encoder object is removed.
76 end();
77}
78
80 if (interrupts_in_use > 0)
81 return;
82 pinMode(pins[0], INPUT_PULLUP);
83 pinMode(pins[1], INPUT_PULLUP);
84 // allow time for a passive R-C filter to charge
85 // through the pullup resistors, before reading
86 // the initial state
88 uint8_t s = 0;
89 if (direct_pins[0].read())
90 s |= 1;
91 if (direct_pins[1].read())
92 s |= 2;
93 state = s;
94
97#if defined(ARDUINO_ARCH_MBED) && !defined(ARDUINO_ARCH_RP2040)
98 // https://github.com/arduino/ArduinoCore-mbed/issues/253
99 pinMode(pins[0], INPUT_PULLUP);
100 pinMode(pins[1], INPUT_PULLUP);
101#endif
102}
103
110
113 if (instance_table[interruptToIndex(interrupt)] != nullptr) {
114 FATAL_ERROR(F("Multiple encoders on the same pin"), 0x7283);
115 return;
116 }
119#ifdef ARDUINO_ARCH_RP2040
122 [](uint gpio, uint32_t) {
123 if (auto arg = instance_table[gpio])
124 arg->update();
125 });
126#else
128 CHANGE);
129#endif
130 }
131}
132
135#ifdef ARDUINO_ARCH_RP2040
137 false);
138#else
140#endif
143 }
144}
145
147
149
150#endif
static interrupt_index_t interruptToIndex(interrupt_index_t i)
Definition AHEncoder.cpp:11
void swap(AHEncoder &a, AHEncoder &b)
Definition AHEncoder.cpp:34
decltype(digitalPinToInterrupt(0)) interrupt_index_t
Definition AHEncoder.cpp:10
#define CS_ENCODER_ARGLIST_SIZE
Definition AHEncoder.hpp:18
constexpr PinMode_t INPUT_PULLUP
DirectPinRead direct_pin_read(uint8_t pin)
#define END_CS_NAMESPACE
#define BEGIN_CS_NAMESPACE
Class for reading quadrature encoders, heavily influenced by http://www.pjrc.com/teensy/td_libs_Encod...
Definition AHEncoder.hpp:22
uint8_t state
Definition AHEncoder.hpp:83
AtomicPosition< int32_t > position
Definition AHEncoder.hpp:85
static isr_func_t get_isr(unsigned interrupt)
Get a pointer to the interrupt handler function for the given interrupt.
static AHEncoder * instance_table[NUM_DIGITAL_PINS]
Array of pointers to all instances with active interrupts.
void attachInterruptCtx(int interrupt)
Register the interrupt handler for this instance.
void detachInterruptCtx(int interrupt)
Un-register the interrupt handler for this instance.
AHEncoder(uint8_t pinA, uint8_t pinB)
Constructor.
Definition AHEncoder.cpp:14
~AHEncoder()
Destructor, detaches the interrupts.
Definition AHEncoder.cpp:72
uint8_t interrupts_in_use
Definition AHEncoder.hpp:82
AH::Array< uint8_t, 2 > pins
Definition AHEncoder.hpp:81
int32_t read()
Read the current absolute position of the encoder.
void end()
Disable the interrupts used by this encoder.
void begin()
Initialize this encoder by enabling the pull-up resistors and attaching the interrupts handlers (if i...
Definition AHEncoder.cpp:79
AHEncoder & operator=(const AHEncoder &)=delete
Copy assignment: copying an Encoder object is semantically meaningless, so it has been deleted.
friend void swap(AHEncoder &a, AHEncoder &b)
Swap two Encoder objects.
Definition AHEncoder.cpp:34
AH::Array< DirectPinRead, 2 > direct_pins
Definition AHEncoder.hpp:84
#define FATAL_ERROR(msg, errc)
Print the error message and error code, and stop the execution.
Definition Error.hpp:57
An array wrapper for easy copying, comparing, and iterating.
Definition Array.hpp:32