Skip to content

Commit

Permalink
Merge pull request #30 from dmadison/v2
Browse files Browse the repository at this point in the history
Remove automatic interrupt attachment
  • Loading branch information
dmadison authored Jan 29, 2024
2 parents 5fa1d59 + 6a43ba3 commit 3cbc406
Show file tree
Hide file tree
Showing 11 changed files with 82 additions and 33 deletions.
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ For more information, [see the article](https://www.partsnotincluded.com/servo-i

ServoInputPin<2> servo;

void setup() {}
void setup() {
servo.attach();
}

void loop() {
float angle = servo.getAngle(); // get angle of servo (0 - 180)
Expand Down
6 changes: 6 additions & 0 deletions examples/BasicAngle/BasicAngle.ino
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ ServoInputPin<2> servo;

void setup() {
Serial.begin(115200);
servo.attach(); // attaches the servo input interrupt

while (servo.available() == false) {
Serial.println("Waiting for servo signal...");
delay(500);
}
}

void loop() {
Expand Down
1 change: 1 addition & 0 deletions examples/Calibration/Calibration.ino
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ ServoInputPin<2> servo;

void setup() {
Serial.begin(115200);
servo.attach(); // attaches the servo input interrupt

int center = servo.getRangeCenter(); // get center value of range
servo.setRange(center, center); // set min/max values to center
Expand Down
1 change: 1 addition & 0 deletions examples/Loopback/Loopback.ino
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ int waitTime = 10; // milliseconds (ms)
void setup() {
Serial.begin(115200);

inputServo.attach(); // attaches the servo input interrupt
outputServo.attach(OutputPin); // attaches the servo on pin 9 to the servo object

while (inputServo.available() == false) {
Expand Down
2 changes: 2 additions & 0 deletions examples/PinChangeInt/PinChange/PinChange.ino
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ ISR(PCINT0_vect) { // pin change ISR handler for Arduino Uno pins D8 - D13
void setup() {
Serial.begin(115200);

// note that we do *not* need to call servo.attach(), because we are
// using our own custom interrupt service routine (ISR)
setInterrupt(); // set pin change interrupt (see above)

while (servo.available() == false) {
Expand Down
2 changes: 2 additions & 0 deletions examples/PinChangeInt/PinChangeLib/PinChangeLib.ino
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ ServoInputPin<pin2> servo2;

void setup() {
Serial.begin(115200);
servo1.attach(); // attaches the first servo input interrupt
servo2.attach(); // attaches the second servo input interrupt

// wait for all servo signals to be read for the first time
while (!ServoInput.available()) {
Expand Down
2 changes: 2 additions & 0 deletions examples/RC_Receiver/RC_Receiver.ino
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ ServoInputPin<ThrottleSignalPin> throttle(ThrottlePulseMin, ThrottlePulseMax);

void setup() {
Serial.begin(115200);
steering.attach(); // attaches the steering servo input interrupt
throttle.attach(); // attaches the throttle servo input interrupt

while (!ServoInput.available()) { // wait for all signals to be ready
Serial.println("Waiting for servo signals...");
Expand Down
1 change: 1 addition & 0 deletions examples/Remapping/Remapping.ino
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ ServoInputPin<2> servo;

void setup() {
Serial.begin(115200);
servo.attach(); // attaches the servo input interrupt

while (servo.available() == false) {
Serial.println("Waiting for servo signal...");
Expand Down
4 changes: 2 additions & 2 deletions keywords.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ getNumSignals KEYWORD2
# ISR
isr KEYWORD2

attachInterrupt KEYWORD2
detachInterrupt KEYWORD2
attach KEYWORD2
detach KEYWORD2

getPin KEYWORD2

Expand Down
14 changes: 7 additions & 7 deletions src/ServoInput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@

#include "ServoInput.h"

boolean ServoInputManager::available() {
bool ServoInputManager::available() {
return allAvailable();
}

boolean ServoInputManager::allAvailable() {
bool ServoInputManager::allAvailable() {
ServoInputSignal* ptr = ServoInputSignal::getHead();
boolean available = false;
bool available = false;

while (ptr != nullptr) {
available = ptr->available();
Expand All @@ -39,9 +39,9 @@ boolean ServoInputManager::allAvailable() {
return available;
}

boolean ServoInputManager::anyAvailable() {
bool ServoInputManager::anyAvailable() {
ServoInputSignal* ptr = ServoInputSignal::getHead();
boolean available = false;
bool available = false;

while (ptr != nullptr) {
available = ptr->available();
Expand Down Expand Up @@ -132,7 +132,7 @@ float ServoInputSignal::getPercent() {
return (float) out / ScaleFactor;
}

boolean ServoInputSignal::getBoolean() {
bool ServoInputSignal::getBoolean() {
const uint16_t pulse = getPulse();
return pulse > getRangeCenter();
}
Expand Down Expand Up @@ -218,7 +218,7 @@ ServoInputSignal* ServoInputSignal::getNext() const {
return next;
}

boolean ServoInputSignal::pulseValidator(unsigned long pulse) {
bool ServoInputSignal::pulseValidator(unsigned long pulse) {
return pulse >= PulseCenter - (PulseValidRange / 2)
&& pulse <= PulseCenter + (PulseValidRange / 2);
}
Expand Down
78 changes: 55 additions & 23 deletions src/ServoInput.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@
class ServoInputSignal {
public:
ServoInputSignal();
~ServoInputSignal();
virtual ~ServoInputSignal();

virtual boolean available() const = 0;
virtual bool available() const = 0;

uint16_t getPulse();
virtual unsigned long getPulseRaw() const = 0;

float getAngle();
float getPercent();

boolean getBoolean();
bool getBoolean();

long map(long outMin, long outMax);

Expand Down Expand Up @@ -73,7 +73,7 @@ class ServoInputSignal {
static const uint16_t PulseValidRange = 2000; // us ( 500 - 2500)
static const uint16_t PulseDefaultRange = 1000; // us (1000 - 2000)

static boolean pulseValidator(unsigned long pulse);
static bool pulseValidator(unsigned long pulse);

long remap(long pulse, long outMin, long outMax) const;

Expand All @@ -96,27 +96,38 @@ class ServoInputPin : public ServoInputSignal {
ServoInputPin<Pin>::PortRegister = SERVOINPUT_PIN_TO_BASEREG(Pin);
#endif
pinMode(Pin, INPUT_PULLUP);
attachInterrupt();

ServoInputPin<Pin>::refCount++;
}

ServoInputPin(uint16_t pMin, uint16_t pMax) : ServoInputPin() {
ServoInputSignal::setRange(pMin, pMax);
}

void attachInterrupt() {
~ServoInputPin() {
ServoInputPin<Pin>::refCount--;
if (ServoInputPin<Pin>::refCount == 0) {
this->detach(); // no more class instances, detach interrupt
}
}

void attach() {
#if !defined(SERVOINPUT_NO_INTERRUPTS)

// Compile-time check that the selected pin supports interrupts
#if !defined(SERVOINPUT_DISABLE_PIN_CHECK) && !defined(SERVOINPUT_SUPPRESS_WARNINGS) && !defined(SERVOINPUT_USING_PCINTLIB)
static_assert(digitalPinToInterrupt(Pin) != NOT_AN_INTERRUPT, "This pin does not support external interrupts!");
#endif

// quit early if the interrupt is already attached
if (ServoInputPin<Pin>::interruptAttached == true) return;

// Interrupt attachment, with pin checks
#if !defined(SERVOINPUT_DISABLE_PIN_CHECK)

// Interrupt attachment, platform support
if (digitalPinToInterrupt(Pin) != NOT_AN_INTERRUPT) { // if pin supports external interrupts
::attachInterrupt(digitalPinToInterrupt(Pin), reinterpret_cast<void(*)()>(isr), CHANGE);
attachInterrupt(digitalPinToInterrupt(Pin), reinterpret_cast<void(*)()>(isr), CHANGE);
}

// Interrupt attachment, PinChangeInterrupt
Expand All @@ -131,21 +142,27 @@ class ServoInputPin : public ServoInputSignal {
// because we have no way of checking whether the pin is supported
// in hardware vs in the library
#else
::attachInterrupt(digitalPinToInterrupt(Pin), reinterpret_cast<void(*)()>(isr), CHANGE);
attachInterrupt(digitalPinToInterrupt(Pin), reinterpret_cast<void(*)()>(isr), CHANGE);
#endif

// set flag to avoid multiple attachment requests
ServoInputPin<Pin>::interruptAttached = true;

#endif
}

void detachInterrupt() {
void detach() {
#if !defined(SERVOINPUT_NO_INTERRUPTS)

// quit early if the interrupt is not attached
if (ServoInputPin<Pin>::interruptAttached == false) return;

// Interrupt detachment, with pin checks
#if !defined(SERVOINPUT_DISABLE_PIN_CHECK)

// Interrupt detachment, platform support
if (digitalPinToInterrupt(Pin) != NOT_AN_INTERRUPT) { // detach external interrupt
::detachInterrupt(digitalPinToInterrupt(Pin));
detachInterrupt(digitalPinToInterrupt(Pin));
}

// Interrupt detachment, PinChangeInterrupt
Expand All @@ -157,16 +174,20 @@ class ServoInputPin : public ServoInputSignal {

// Interrupt detachment, no pin checks
#else
::detachInterrupt(digitalPinToInterrupt(Pin));
detachInterrupt(digitalPinToInterrupt(Pin));
#endif

// set flag to show that we've detached successfully
ServoInputPin<Pin>::interruptAttached = false;

#endif
}

boolean available() const {
boolean change = ServoInputPin<Pin>::changed; // store temp version of volatile flag
bool available() const {
bool change = ServoInputPin<Pin>::changed; // store temp version of volatile flag

if (change == true) {
boolean pulseValid = ServoInputSignal::pulseValidator(getPulseInternal());
bool pulseValid = ServoInputSignal::pulseValidator(getPulseInternal());

if (pulseValid == false) {
ServoInputPin<Pin>::changed = change = false; // pulse is not valid, so we can reset (ignore) the 'changed' flag
Expand All @@ -175,10 +196,10 @@ class ServoInputPin : public ServoInputSignal {
return change;
}

boolean read() {
bool read() {
unsigned long pulse = pulseIn(Pin, HIGH, 25000); // 20 ms per + 5 ms of grace

boolean validPulse = pulseValidator(pulse);
bool validPulse = pulseValidator(pulse);
if (validPulse == true) {
pulseDuration = pulse; // pulse is valid, store result
}
Expand All @@ -199,9 +220,9 @@ class ServoInputPin : public ServoInputSignal {
static unsigned long start = 0;

#ifdef SERVOINPUT_PIN_SPECIALIZATION
const boolean state = SERVOINPUT_DIRECT_PIN_READ(PortRegister, PinMask);
const bool state = SERVOINPUT_DIRECT_PIN_READ(PortRegister, PinMask);
#else
const boolean state = digitalRead(Pin);
const bool state = digitalRead(Pin);
#endif

if (state == HIGH) { // rising edge
Expand All @@ -214,7 +235,7 @@ class ServoInputPin : public ServoInputSignal {
}

protected:
static volatile boolean changed;
static volatile bool changed;
static volatile unsigned long pulseDuration;

static unsigned long getPulseInternal() {
Expand All @@ -226,27 +247,38 @@ class ServoInputPin : public ServoInputSignal {
return pulse;
}

private:
// class instance counter, for automatic interrupt detachment
static uint8_t refCount;

// flag to indicate whether the class interrupt is attached, to
// avoid making multiple calls to the platform attachment function
static bool interruptAttached;

#ifdef SERVOINPUT_PIN_SPECIALIZATION
private:
static SERVOINPUT_IO_REG_TYPE PinMask; // bitmask to isolate the I/O pin
static volatile SERVOINPUT_IO_REG_TYPE* PortRegister; // pointer to the I/O register for the pin
#endif
};

template<uint8_t Pin> uint8_t ServoInputPin<Pin>::refCount = 0;
template<uint8_t Pin> bool ServoInputPin<Pin>::interruptAttached = false;

#ifdef SERVOINPUT_PIN_SPECIALIZATION
template<uint8_t Pin> SERVOINPUT_IO_REG_TYPE ServoInputPin<Pin>::PinMask;
template<uint8_t Pin> volatile SERVOINPUT_IO_REG_TYPE* ServoInputPin<Pin>::PortRegister;
#endif

template<uint8_t Pin> volatile boolean ServoInputPin<Pin>::changed = false;
template<uint8_t Pin> volatile bool ServoInputPin<Pin>::changed = false;
template<uint8_t Pin> volatile unsigned long ServoInputPin<Pin>::pulseDuration = 0;


class ServoInputManager {
public:
static boolean available();
static boolean allAvailable();
static boolean anyAvailable();
static bool available();
static bool allAvailable();
static bool anyAvailable();

static uint8_t getNumSignals();
};
Expand Down

0 comments on commit 3cbc406

Please sign in to comment.