mirror of
https://github.com/meshtastic/firmware.git
synced 2025-08-17 10:43:24 +00:00
RotaryEncoderInterruptBase
This commit is contained in:
parent
6eb2b33124
commit
c7e62142e9
13
src/plugins/input/HardwareInput.h
Normal file
13
src/plugins/input/HardwareInput.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define INPUT_EVENT_UP 17
|
||||||
|
#define INPUT_EVENT_DOWN 18
|
||||||
|
#define INPUT_EVENT_LEFT 19
|
||||||
|
#define INPUT_EVENT_RIGHT 20
|
||||||
|
#define INPUT_EVENT_SELECT '\n'
|
||||||
|
#define INPUT_EVENT_BACK 27
|
||||||
|
#define INPUT_EVENT_CANCEL 24
|
||||||
|
|
||||||
|
typedef struct _InputEvent {
|
||||||
|
char inputEvent;
|
||||||
|
} InputEvent;
|
142
src/plugins/input/RotaryEncoderInterruptBase.cpp
Normal file
142
src/plugins/input/RotaryEncoderInterruptBase.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
#include "configuration.h"
|
||||||
|
#include "RotaryEncoderInterruptBase.h"
|
||||||
|
|
||||||
|
/*#define PIN_PUSH 21
|
||||||
|
#define PIN_A 22
|
||||||
|
#define PIN_B 23
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
RotaryEncoderInterruptBase *cannedMessagePlugin;
|
||||||
|
|
||||||
|
void IRAM_ATTR EXT_INT_PUSH()
|
||||||
|
{
|
||||||
|
cannedMessagePlugin->pressed();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR EXT_INT_DIRECTION_A()
|
||||||
|
{
|
||||||
|
cannedMessagePlugin->directionA();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR EXT_INT_DIRECTION_B()
|
||||||
|
{
|
||||||
|
cannedMessagePlugin->directionB();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(
|
||||||
|
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||||
|
char eventCw, char eventCcw, char eventPressed,
|
||||||
|
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress) :
|
||||||
|
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)()) :
|
||||||
|
SinglePortPlugin("rotaryi", PortNum_TEXT_MESSAGE_APP),
|
||||||
|
concurrency::OSThread("RotaryEncoderInterruptBase")
|
||||||
|
{
|
||||||
|
this->_pinA = pinA;
|
||||||
|
this->_pinB = pinB;
|
||||||
|
this->_eventCw = eventCw;
|
||||||
|
this->_eventCcw = eventCcw;
|
||||||
|
this->_eventPressed = eventPressed;
|
||||||
|
|
||||||
|
// TODO: make pins configurable
|
||||||
|
pinMode(pinPress, INPUT_PULLUP);
|
||||||
|
pinMode(this->_pinA, INPUT_PULLUP);
|
||||||
|
pinMode(this->_pinB, INPUT_PULLUP);
|
||||||
|
// attachInterrupt(pinPress, onIntPress, RISING);
|
||||||
|
attachInterrupt(pinPress, onIntPress, RISING);
|
||||||
|
attachInterrupt(this->_pinA, onIntA, CHANGE);
|
||||||
|
attachInterrupt(this->_pinB, onIntB, CHANGE);
|
||||||
|
this->rotaryLevelA = digitalRead(this->_pinA);
|
||||||
|
this->rotaryLevelB = digitalRead(this->_pinB);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||||
|
{
|
||||||
|
if (this->action == ACTION_PRESSED)
|
||||||
|
{
|
||||||
|
InputEvent e;
|
||||||
|
e.inputEvent = INPUT_EVENT_SELECT;
|
||||||
|
this->notifyObservers(&e);
|
||||||
|
}
|
||||||
|
return 30000;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RotaryEncoderInterruptBase::intPressHandler()
|
||||||
|
{
|
||||||
|
this->action = ACTION_PRESSED;
|
||||||
|
runned(millis());
|
||||||
|
setInterval(20);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Rotary action implementation.
|
||||||
|
* We assume, the following pin setup:
|
||||||
|
* A --||
|
||||||
|
* GND --||]========
|
||||||
|
* B --||
|
||||||
|
*
|
||||||
|
* @return The new level of the actual pin (that is actualPinCurrentLevel).
|
||||||
|
*/
|
||||||
|
void RotaryEncoderInterruptBase::intAHandler()
|
||||||
|
{
|
||||||
|
// CW rotation (at least on most common rotary encoders)
|
||||||
|
int currentLevelA = digitalRead(this->_pinA);
|
||||||
|
if (this->rotaryLevelA == currentLevelA)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->rotaryLevelA = currentLevelA;
|
||||||
|
bool pinARaising = currentLevelA == HIGH;
|
||||||
|
if (pinARaising && (this->rotaryLevelB == LOW))
|
||||||
|
{
|
||||||
|
if (this->rotaryStateCCW == EVENT_CLEARED)
|
||||||
|
{
|
||||||
|
this->rotaryStateCCW = EVENT_OCCURRED;
|
||||||
|
if ((this->action == ACTION_NONE)
|
||||||
|
|| (this->action == ACTION_CCW))
|
||||||
|
{
|
||||||
|
this->action = ACTION_CW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!pinARaising && (this->rotaryLevelB == HIGH))
|
||||||
|
{
|
||||||
|
// Logic to prevent bouncing.
|
||||||
|
this->rotaryStateCCW = EVENT_CLEARED;
|
||||||
|
}
|
||||||
|
runned(millis());
|
||||||
|
setInterval(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RotaryEncoderInterruptBase::intBHandler()
|
||||||
|
{
|
||||||
|
// CW rotation (at least on most common rotary encoders)
|
||||||
|
int currentLevelB = digitalRead(this->_pinB);
|
||||||
|
if (this->rotaryLevelB == currentLevelB)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->rotaryLevelB = currentLevelB;
|
||||||
|
bool pinBRaising = currentLevelB == HIGH;
|
||||||
|
if (pinBRaising && (this->rotaryLevelA == LOW))
|
||||||
|
{
|
||||||
|
if (this->rotaryStateCW == EVENT_CLEARED)
|
||||||
|
{
|
||||||
|
this->rotaryStateCW = EVENT_OCCURRED;
|
||||||
|
if ((this->action == ACTION_NONE)
|
||||||
|
|| (this->action == ACTION_CCW))
|
||||||
|
{
|
||||||
|
this->action = ACTION_CW;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!pinBRaising && (this->rotaryLevelA == HIGH))
|
||||||
|
{
|
||||||
|
// Logic to prevent bouncing.
|
||||||
|
this->rotaryStateCW = EVENT_CLEARED;
|
||||||
|
}
|
||||||
|
runned(millis());
|
||||||
|
setInterval(50);
|
||||||
|
}
|
50
src/plugins/input/RotaryEncoderInterruptBase.h
Normal file
50
src/plugins/input/RotaryEncoderInterruptBase.h
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "SinglePortPlugin.h"
|
||||||
|
#include "HardwareInput.h"
|
||||||
|
|
||||||
|
enum RotaryEncoderInterruptBaseStateType
|
||||||
|
{
|
||||||
|
EVENT_OCCURRED,
|
||||||
|
EVENT_CLEARED
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RotaryEncoderInterruptBaseActionType
|
||||||
|
{
|
||||||
|
ACTION_NONE,
|
||||||
|
ACTION_PRESSED,
|
||||||
|
ACTION_CW,
|
||||||
|
ACTION_CCW
|
||||||
|
};
|
||||||
|
|
||||||
|
class RotaryEncoderInterruptBase :
|
||||||
|
public SinglePortPlugin,
|
||||||
|
public Observable<const InputEvent *>,
|
||||||
|
private concurrency::OSThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RotaryEncoderInterruptBase(
|
||||||
|
uint8_t pinA, uint8_t pinB, uint8_t pinPress,
|
||||||
|
char eventCw, char eventCcw, char eventPressed,
|
||||||
|
// std::function<void(void)> onIntA, std::function<void(void)> onIntB, std::function<void(void)> onIntPress);
|
||||||
|
void (*onIntA)(), void (*onIntB)(), void (*onIntPress)());
|
||||||
|
void intPressHandler();
|
||||||
|
void intAHandler();
|
||||||
|
void intBHandler();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual int32_t runOnce();
|
||||||
|
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = EVENT_CLEARED;
|
||||||
|
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = EVENT_CLEARED;
|
||||||
|
volatile int rotaryLevelA = LOW;
|
||||||
|
volatile int rotaryLevelB = LOW;
|
||||||
|
volatile RotaryEncoderInterruptBaseActionType action = ACTION_NONE;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t _pinA;
|
||||||
|
uint8_t _pinB;
|
||||||
|
char _eventCw;
|
||||||
|
char _eventCcw;
|
||||||
|
char _eventPressed;
|
||||||
|
};
|
||||||
|
|
||||||
|
RotaryEncoderInterruptBase *RotaryEncoderInterruptBase;
|
Loading…
Reference in New Issue
Block a user