diff --git a/src/ClickEncoder.cpp b/src/ClickEncoder.cpp index 3684db3..c16e099 100644 --- a/src/ClickEncoder.cpp +++ b/src/ClickEncoder.cpp @@ -10,6 +10,18 @@ // ---------------------------------------------------------------------------- #include "ClickEncoder.h" +#if defined(ESP8266) +# if defined(IRAM_ATTR) +# define CLICK_ENCODER_ISR_ATTR IRAM_ATTR +# elif defined(ICACHE_RAM_ATTR) +# define CLICK_ENCODER_ISR_ATTR ICACHE_RAM_ATTR +# else +# error "ClickEncoder requires IRAM_ATTR or ICACHE_RAM_ATTR on ESP8266" +# endif +#else +# define CLICK_ENCODER_ISR_ATTR +#endif + // ---------------------------------------------------------------------------- // Button configuration (values for 1ms timer service calls) @@ -112,7 +124,7 @@ AnalogButton::AnalogButton(int8_t BTN, int16_t rangeLow, int16_t rangeHigh) : Cl // ---------------------------------------------------------------------------- // call this every 1 millisecond via timer ISR // -void ClickEncoder::service(void) +void CLICK_ENCODER_ISR_ATTR ClickEncoder::service(void) { bool moved = false; @@ -170,24 +182,29 @@ void ClickEncoder::service(void) } } } - // handle button - // #ifndef WITHOUT_BUTTON +#if defined(ESP8266) + if (!analogInput) { + serviceButton(); + } +#else + serviceButton(); +#endif +#endif + +} + +#ifndef WITHOUT_BUTTON +void CLICK_ENCODER_ISR_ATTR ClickEncoder::serviceButton(void) +{ unsigned long currentMillis = millis(); unsigned long millisSinceLastCheck = currentMillis - lastButtonCheck; - if ((pinBTN > 0 || (pinBTN == 0 && buttonOnPinZeroEnabled)) // check button only, if a pin has been provided - && (millisSinceLastCheck >= ENC_BUTTONINTERVAL)) // checking button is sufficient every 10-30ms - { + if ((pinBTN > 0 || (pinBTN == 0 && buttonOnPinZeroEnabled)) + && (millisSinceLastCheck >= ENC_BUTTONINTERVAL)) + { lastButtonCheck = currentMillis; bool pinRead = getPinState(); - - - - - - - if (pinRead == !pinsActive) { // key is now up if (keyDownTicks > 1) { //Make sure key was down through 1 complete tick to prevent random transients from registering as click @@ -211,14 +228,14 @@ void ClickEncoder::service(void) keyDownTicks = 0; } - + if (pinRead == pinsActive) { // key is down if ((keyDownTicks > (buttonHoldTime)) && (buttonHeldEnabled)) { button = Held; } keyDownTicks += millisSinceLastCheck; } - + if (doubleClickTicks > 0) { doubleClickTicks -= (uint16_t)constrain(min(millisSinceLastCheck, (unsigned long)doubleClickTicks), 0, 65536); if (doubleClickTicks == 0) { @@ -226,9 +243,8 @@ void ClickEncoder::service(void) } } } -#endif // WITHOUT_BUTTON - } +#endif // ---------------------------------------------------------------------------- @@ -289,6 +305,11 @@ void ClickEncoder::resetEncoder(void) #ifndef WITHOUT_BUTTON ClickEncoder::Button ClickEncoder::getButton(void) { +#if defined(ESP8266) + if (analogInput) { + serviceButton(); + } +#endif noInterrupts(); ClickEncoder::Button ret = button; if (button != ClickEncoder::Held && ret != ClickEncoder::Open) { @@ -299,7 +320,7 @@ ClickEncoder::Button ClickEncoder::getButton(void) return ret; } -bool ClickEncoder::getPinState() { +bool CLICK_ENCODER_ISR_ATTR ClickEncoder::getPinState() { bool pinState; if (analogInput) { int16_t pinValue = analogRead(pinBTN); @@ -311,3 +332,4 @@ bool ClickEncoder::getPinState() { } #endif +#undef CLICK_ENCODER_ISR_ATTR diff --git a/src/ClickEncoder.h b/src/ClickEncoder.h index 9bbe856..e82b9d9 100644 --- a/src/ClickEncoder.h +++ b/src/ClickEncoder.h @@ -173,6 +173,7 @@ class ClickEncoder unsigned long lastButtonCheck = 0; int16_t anlogActiveRangeLow = 0; int16_t anlogActiveRangeHigh = 0; + void serviceButton(void); bool getPinState(); #endif }; diff --git a/test/esp8266_analog_button_test.cpp b/test/esp8266_analog_button_test.cpp new file mode 100644 index 0000000..324bc33 --- /dev/null +++ b/test/esp8266_analog_button_test.cpp @@ -0,0 +1,74 @@ +#include + +#include "ClickEncoder.h" + +static unsigned long fakeMillis; +static int fakeAnalogValue; +static int fakeDigitalValue; +static unsigned int analogReadCalls; +static unsigned int digitalReadCalls; + +unsigned long millis(void) +{ + return fakeMillis; +} + +int analogRead(uint8_t) +{ + ++analogReadCalls; + return fakeAnalogValue; +} + +int digitalRead(uint8_t) +{ + ++digitalReadCalls; + return fakeDigitalValue; +} + +void pinMode(uint8_t, uint8_t) +{ +} + +void noInterrupts(void) +{ +} + +void interrupts(void) +{ +} + +int main(void) +{ + fakeAnalogValue = 150; + AnalogButton analogButton(1, 100, 200); + +#if defined(ESP8266) + fakeMillis = 10; + assert(analogButton.getButton() == ClickEncoder::Open); + assert(analogReadCalls == 1); + + fakeMillis = 20; + analogButton.service(); + assert(analogReadCalls == 1); + + fakeAnalogValue = 900; + assert(analogButton.getButton() == ClickEncoder::Open); + assert(analogReadCalls == 2); + + fakeMillis = 410; + assert(analogButton.getButton() == ClickEncoder::Clicked); + assert(analogReadCalls == 3); + + fakeDigitalValue = LOW; + DigitalButton digitalButton(1); + fakeMillis = 10; + digitalButton.service(); + assert(digitalReadCalls == 1); +#else + fakeMillis = 10; + analogButton.service(); + assert(analogReadCalls == 1); +#endif + + return 0; +} diff --git a/test/support/Arduino.h b/test/support/Arduino.h new file mode 100644 index 0000000..e32fc98 --- /dev/null +++ b/test/support/Arduino.h @@ -0,0 +1,21 @@ +#ifndef TEST_SUPPORT_ARDUINO_H +#define TEST_SUPPORT_ARDUINO_H + +#include + +#define LOW 0x0 +#define HIGH 0x1 +#define INPUT 0x0 +#define INPUT_PULLUP 0x2 + +unsigned long millis(void); +int analogRead(uint8_t pin); +int digitalRead(uint8_t pin); +void pinMode(uint8_t pin, uint8_t mode); +void noInterrupts(void); +void interrupts(void); + +#define min(a, b) ((a) < (b) ? (a) : (b)) +#define constrain(value, lower, upper) ((value) < (lower) ? (lower) : ((value) > (upper) ? (upper) : (value))) + +#endif