mirror of
https://github.com/meshtastic/firmware.git
synced 2025-12-30 14:40:40 +00:00
Relocate 'input' folder.
This commit is contained in:
18
src/input/InputBroker.cpp
Normal file
18
src/input/InputBroker.cpp
Normal file
@@ -0,0 +1,18 @@
|
||||
#include "InputBroker.h"
|
||||
|
||||
InputBroker *inputBroker;
|
||||
|
||||
InputBroker::InputBroker()
|
||||
{
|
||||
};
|
||||
|
||||
void InputBroker::registerSource(Observable<const InputEvent *> *source)
|
||||
{
|
||||
this->inputEventObserver.observe(source);
|
||||
}
|
||||
|
||||
int InputBroker::handleInputEvent(const InputEvent *event)
|
||||
{
|
||||
this->notifyObservers(event);
|
||||
return 0;
|
||||
}
|
||||
22
src/input/InputBroker.h
Normal file
22
src/input/InputBroker.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "Observer.h"
|
||||
|
||||
typedef struct _InputEvent {
|
||||
const char* source;
|
||||
char inputEvent;
|
||||
} InputEvent;
|
||||
class InputBroker :
|
||||
public Observable<const InputEvent *>
|
||||
{
|
||||
CallbackObserver<InputBroker, const InputEvent *> inputEventObserver =
|
||||
CallbackObserver<InputBroker, const InputEvent *>(this, &InputBroker::handleInputEvent);
|
||||
|
||||
public:
|
||||
InputBroker();
|
||||
void registerSource(Observable<const InputEvent *> *source);
|
||||
|
||||
protected:
|
||||
int handleInputEvent(const InputEvent *event);
|
||||
};
|
||||
|
||||
extern InputBroker *inputBroker;
|
||||
148
src/input/RotaryEncoderInterruptBase.cpp
Normal file
148
src/input/RotaryEncoderInterruptBase.cpp
Normal file
@@ -0,0 +1,148 @@
|
||||
#include "configuration.h"
|
||||
#include "RotaryEncoderInterruptBase.h"
|
||||
|
||||
RotaryEncoderInterruptBase::RotaryEncoderInterruptBase(
|
||||
const char *name) :
|
||||
concurrency::OSThread(name)
|
||||
{
|
||||
this->_originName = name;
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptBase::init(
|
||||
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)())
|
||||
{
|
||||
this->_pinA = pinA;
|
||||
this->_pinB = pinB;
|
||||
this->_eventCw = eventCw;
|
||||
this->_eventCcw = eventCcw;
|
||||
this->_eventPressed = eventPressed;
|
||||
|
||||
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);
|
||||
DEBUG_MSG("Rotary initialized (%d, %d, %d)\n",
|
||||
this->_pinA, this->_pinB, pinPress);
|
||||
}
|
||||
|
||||
|
||||
int32_t RotaryEncoderInterruptBase::runOnce()
|
||||
{
|
||||
InputEvent e;
|
||||
e.inputEvent = InputEventChar_NULL;
|
||||
e.source = this->_originName;
|
||||
|
||||
if (this->action == ROTARY_ACTION_PRESSED)
|
||||
{
|
||||
DEBUG_MSG("Rotary event Press\n");
|
||||
e.inputEvent = this->_eventPressed;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CW)
|
||||
{
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCw;
|
||||
}
|
||||
else if (this->action == ROTARY_ACTION_CCW)
|
||||
{
|
||||
DEBUG_MSG("Rotary event CW\n");
|
||||
e.inputEvent = this->_eventCcw;
|
||||
}
|
||||
|
||||
if (e.inputEvent != InputEventChar_NULL)
|
||||
{
|
||||
this->notifyObservers(&e);
|
||||
}
|
||||
|
||||
this->action = ROTARY_ACTION_NONE;
|
||||
|
||||
return 30000; // TODO: technically this can be MAX_INT
|
||||
}
|
||||
|
||||
|
||||
void RotaryEncoderInterruptBase::intPressHandler()
|
||||
{
|
||||
this->action = ROTARY_ACTION_PRESSED;
|
||||
setIntervalFromNow(20); // TODO: this modifies a non-volatile variable!
|
||||
}
|
||||
|
||||
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;
|
||||
intHandler(
|
||||
currentLevelA == HIGH,
|
||||
this->rotaryLevelB,
|
||||
ROTARY_ACTION_CCW,
|
||||
this->rotaryStateCCW);
|
||||
}
|
||||
|
||||
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;
|
||||
this->rotaryStateCW = intHandler(
|
||||
currentLevelB == HIGH,
|
||||
this->rotaryLevelA,
|
||||
ROTARY_ACTION_CW,
|
||||
this->rotaryStateCW);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Rotary action implementation.
|
||||
* We assume, the following pin setup:
|
||||
* A --||
|
||||
* GND --||]========
|
||||
* B --||
|
||||
*
|
||||
* @return The new state for rotary pin.
|
||||
*/
|
||||
RotaryEncoderInterruptBaseStateType RotaryEncoderInterruptBase::intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state)
|
||||
{
|
||||
RotaryEncoderInterruptBaseStateType newState =
|
||||
state;
|
||||
if (actualPinRaising && (otherPinLevel == LOW))
|
||||
{
|
||||
if (state == ROTARY_EVENT_CLEARED)
|
||||
{
|
||||
newState = ROTARY_EVENT_OCCURRED;
|
||||
if ((this->action != ROTARY_ACTION_PRESSED)
|
||||
&& (this->action != action))
|
||||
{
|
||||
this->action = action;
|
||||
DEBUG_MSG("Rotary action\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!actualPinRaising && (otherPinLevel == HIGH))
|
||||
{
|
||||
// Logic to prevent bouncing.
|
||||
newState = ROTARY_EVENT_CLEARED;
|
||||
}
|
||||
setIntervalFromNow(50); // TODO: this modifies a non-volatile variable!
|
||||
|
||||
return newState;
|
||||
}
|
||||
57
src/input/RotaryEncoderInterruptBase.h
Normal file
57
src/input/RotaryEncoderInterruptBase.h
Normal file
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "SinglePortPlugin.h" // TODO: what header file to include?
|
||||
#include "InputBroker.h"
|
||||
|
||||
enum RotaryEncoderInterruptBaseStateType
|
||||
{
|
||||
ROTARY_EVENT_OCCURRED,
|
||||
ROTARY_EVENT_CLEARED
|
||||
};
|
||||
|
||||
enum RotaryEncoderInterruptBaseActionType
|
||||
{
|
||||
ROTARY_ACTION_NONE,
|
||||
ROTARY_ACTION_PRESSED,
|
||||
ROTARY_ACTION_CW,
|
||||
ROTARY_ACTION_CCW
|
||||
};
|
||||
|
||||
class RotaryEncoderInterruptBase :
|
||||
public Observable<const InputEvent *>,
|
||||
private concurrency::OSThread
|
||||
{
|
||||
public:
|
||||
RotaryEncoderInterruptBase(
|
||||
const char *name);
|
||||
void init(
|
||||
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();
|
||||
RotaryEncoderInterruptBaseStateType intHandler(
|
||||
bool actualPinRaising,
|
||||
int otherPinLevel,
|
||||
RotaryEncoderInterruptBaseActionType action,
|
||||
RotaryEncoderInterruptBaseStateType state);
|
||||
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCW = ROTARY_EVENT_CLEARED;
|
||||
volatile RotaryEncoderInterruptBaseStateType rotaryStateCCW = ROTARY_EVENT_CLEARED;
|
||||
volatile int rotaryLevelA = LOW;
|
||||
volatile int rotaryLevelB = LOW;
|
||||
volatile RotaryEncoderInterruptBaseActionType action = ROTARY_ACTION_NONE;
|
||||
|
||||
private:
|
||||
uint8_t _pinA;
|
||||
uint8_t _pinB;
|
||||
char _eventCw;
|
||||
char _eventCcw;
|
||||
char _eventPressed;
|
||||
const char *_originName;
|
||||
};
|
||||
51
src/input/RotaryEncoderInterruptImpl1.cpp
Normal file
51
src/input/RotaryEncoderInterruptImpl1.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
#include "RotaryEncoderInterruptImpl1.h"
|
||||
#include "InputBroker.h"
|
||||
|
||||
RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
|
||||
RotaryEncoderInterruptImpl1::RotaryEncoderInterruptImpl1() :
|
||||
RotaryEncoderInterruptBase(
|
||||
"rotEnc1")
|
||||
{
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::init()
|
||||
{
|
||||
if (!radioConfig.preferences.rotary1_enabled)
|
||||
{
|
||||
// Input device is disabled.
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t pinA = radioConfig.preferences.rotary1_pin_a;
|
||||
uint8_t pinB = radioConfig.preferences.rotary1_pin_b;
|
||||
uint8_t pinPress = radioConfig.preferences.rotary1_pin_press;
|
||||
char eventCw =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_cw);
|
||||
char eventCcw =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_ccw);
|
||||
char eventPressed =
|
||||
static_cast<char>(radioConfig.preferences.rotary1_event_press);
|
||||
|
||||
//radioConfig.preferences.ext_notification_plugin_output
|
||||
RotaryEncoderInterruptBase::init(
|
||||
pinA, pinB, pinPress,
|
||||
eventCw, eventCcw, eventPressed,
|
||||
RotaryEncoderInterruptImpl1::handleIntA,
|
||||
RotaryEncoderInterruptImpl1::handleIntB,
|
||||
RotaryEncoderInterruptImpl1::handleIntPressed);
|
||||
inputBroker->registerSource(this);
|
||||
}
|
||||
|
||||
void RotaryEncoderInterruptImpl1::handleIntA()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intAHandler();
|
||||
}
|
||||
void RotaryEncoderInterruptImpl1::handleIntB()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intBHandler();
|
||||
}
|
||||
void RotaryEncoderInterruptImpl1::handleIntPressed()
|
||||
{
|
||||
rotaryEncoderInterruptImpl1->intPressHandler();
|
||||
}
|
||||
22
src/input/RotaryEncoderInterruptImpl1.h
Normal file
22
src/input/RotaryEncoderInterruptImpl1.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "RotaryEncoderInterruptBase.h"
|
||||
|
||||
/**
|
||||
* @brief The idea behind this class to have static methods for the event handlers.
|
||||
* Check attachInterrupt() at RotaryEncoderInteruptBase.cpp
|
||||
* Technically you can have as many rotary encoders hardver attached
|
||||
* to your device as you wish, but you always need to have separate event
|
||||
* handlers, thus you need to have a RotaryEncoderInterrupt implementation.
|
||||
*/
|
||||
class RotaryEncoderInterruptImpl1 :
|
||||
public RotaryEncoderInterruptBase
|
||||
{
|
||||
public:
|
||||
RotaryEncoderInterruptImpl1();
|
||||
void init();
|
||||
static void handleIntA();
|
||||
static void handleIntB();
|
||||
static void handleIntPressed();
|
||||
};
|
||||
|
||||
extern RotaryEncoderInterruptImpl1 *rotaryEncoderInterruptImpl1;
|
||||
Reference in New Issue
Block a user