Factor pin-reading logic into a new set of classes.
This commit is contained in:
parent
a4f00a0a23
commit
8ebc1a5523
55
Button.cpp
55
Button.cpp
|
@ -5,60 +5,28 @@
|
|||
|
||||
using namespace admux;
|
||||
|
||||
Button::Button(uint8_t vbutton) {
|
||||
Button::Button(uint8_t vbutton, Reader* reader) {
|
||||
this->vbutton = vbutton;
|
||||
this->reader = reader;
|
||||
}
|
||||
|
||||
void Button::ReleaseButtons(Joystick* js) {
|
||||
js->ReleaseButton(vbutton);
|
||||
}
|
||||
|
||||
// TODO: make analog_only work... how to handle that with debouncer?
|
||||
SwitchButton::SwitchButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux, bool analog_only) : Button(vbutton) {
|
||||
this->mux = mux;
|
||||
|
||||
uint8_t mode = INPUT;
|
||||
if (pullup) {
|
||||
this->inverted = true;
|
||||
mode = INPUT_PULLUP;
|
||||
}
|
||||
|
||||
if (mux == NULL) this->bouncer.attach(pin, mode);
|
||||
else {
|
||||
this->bouncer.attach(mux->signalPin().pin, mode);
|
||||
this->channel_id = pin;
|
||||
}
|
||||
}
|
||||
|
||||
bool SwitchButton::BouncerUpdate() {
|
||||
if (mux != NULL) {
|
||||
mux->channel(channel_id);
|
||||
delayMicroseconds(500);
|
||||
}
|
||||
|
||||
return bouncer.update();
|
||||
}
|
||||
|
||||
bool SwitchButton::On() {
|
||||
bool state = bouncer.rose();
|
||||
if (inverted) state = bouncer.fell();
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
PassthruButton::PassthruButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux, bool analog_only) : SwitchButton(pin, vbutton, pullup, mux, analog_only) {
|
||||
PassthruButton::PassthruButton(uint8_t vbutton, Reader* reader) : Button(vbutton, reader) {
|
||||
this->type = BUTTON_PASSTHRU;
|
||||
}
|
||||
|
||||
bool PassthruButton::Update(Joystick* js) {
|
||||
if (!BouncerUpdate()) return false;
|
||||
if (On()) js->PressButton(vbutton);
|
||||
if (!reader->Update()) return false;
|
||||
if (reader->On()) js->PressButton(vbutton);
|
||||
else js->ReleaseButton(vbutton);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
LatchedButton::LatchedButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux, bool analog_only) : SwitchButton(pin, vbutton, pullup, mux, analog_only) {
|
||||
LatchedButton::LatchedButton(uint8_t vbutton, Reader* reader) : Button(vbutton, reader) {
|
||||
this->type = BUTTON_LATCHED_MOMENTARY;
|
||||
this->pressed = false;
|
||||
}
|
||||
|
@ -131,12 +99,6 @@ bool PulsedButton::Update(Joystick* js) {
|
|||
return true;
|
||||
}
|
||||
|
||||
void PulsedButton::ReleaseButtons(Joystick* js) {
|
||||
Button::ReleaseButtons(js);
|
||||
if (type == BUTTON_PULSED_DOUBLE_ACTION_SPLIT) js->ReleaseButton(vbutton2);
|
||||
}
|
||||
|
||||
|
||||
|
||||
EncoderButton::EncoderButton(uint8_t pin1, uint8_t pin2, uint8_t vbutton) : Button(vbutton) {
|
||||
this->type = ENCODER_PULSED_SPLIT;
|
||||
|
@ -173,8 +135,3 @@ bool EncoderButton::Update(Joystick* js) {
|
|||
last_value = new_value;
|
||||
return changed;
|
||||
}
|
||||
|
||||
void EncoderButton::ReleaseButtons(Joystick* js) {
|
||||
Button::ReleaseButtons(js);
|
||||
js->ReleaseButton(vbutton2);
|
||||
}
|
||||
|
|
38
Button.h
38
Button.h
|
@ -2,8 +2,7 @@
|
|||
#define _BUTTON_H_
|
||||
|
||||
#include <Encoder.h>
|
||||
#include <Mux.h>
|
||||
#include <Bounce2.h>
|
||||
#include "Reader.h"
|
||||
|
||||
using namespace admux;
|
||||
|
||||
|
@ -24,53 +23,35 @@ enum ButtonType {
|
|||
// * an update method.
|
||||
class Button {
|
||||
public:
|
||||
Button(uint8_t vbutton);
|
||||
Button(uint8_t vbutton, Reader* reader);
|
||||
virtual bool Update(Joystick* js) = 0;
|
||||
virtual void ReleaseButtons(Joystick* js);
|
||||
ButtonType type;
|
||||
|
||||
protected:
|
||||
uint8_t vbutton;
|
||||
Reader *reader;
|
||||
};
|
||||
|
||||
// An abstract class for a momentary/pushbutton or toggle switch. Special properties:
|
||||
// * needs to be explicitly debounced
|
||||
// * may use the microcontroller's built-in pullup resistor mode to eliminate noise
|
||||
// * may be attached to a multiplexer. In this case, the `pin` value will be treated as a multiplexer channel,
|
||||
// and the multiplexer logic will be automatically invoked by Update()
|
||||
class SwitchButton : public Button {
|
||||
class PassthruButton : public Button {
|
||||
public:
|
||||
SwitchButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux, bool analog_only);
|
||||
bool BouncerUpdate(); // returns true if the pin's status has changed
|
||||
bool On();
|
||||
|
||||
protected:
|
||||
Bounce bouncer;
|
||||
bool inverted;
|
||||
Mux *mux;
|
||||
uint8_t channel_id;
|
||||
};
|
||||
|
||||
class PassthruButton : public SwitchButton {
|
||||
public:
|
||||
PassthruButton(uint8_t pin, uint8_t vbutton, bool pullup = true, Mux* mux = NULL, bool analog_only = false);
|
||||
PassthruButton(uint8_t vbutton, Reader* reader);
|
||||
bool Update(Joystick* js);
|
||||
};
|
||||
|
||||
class LatchedButton : public SwitchButton {
|
||||
class LatchedButton : public Button {
|
||||
public:
|
||||
LatchedButton(uint8_t pin, uint8_t vbutton, bool pullup = true, Mux* mux = NULL, bool analog_only = false);
|
||||
LatchedButton(uint8_t vbutton, Reader* reader);
|
||||
bool Update(Joystick* js);
|
||||
|
||||
protected:
|
||||
bool pressed;
|
||||
};
|
||||
|
||||
class PulsedButton : public SwitchButton {
|
||||
class PulsedButton : public Button {
|
||||
public:
|
||||
PulsedButton(uint8_t pin, uint8_t vbutton, bool double_action = false, bool split = false, bool pullup = true, Mux* mux = NULL, bool analog_only = false);
|
||||
PulsedButton(uint8_t vbutton, Reader* reader, bool double_action = false, bool split = false);
|
||||
bool Update(Joystick* js);
|
||||
void ReleaseButtons(Joystick* js);
|
||||
|
||||
protected:
|
||||
bool double_action;
|
||||
|
@ -84,7 +65,6 @@ class EncoderButton : public Button {
|
|||
public:
|
||||
EncoderButton(uint8_t pin1, uint8_t pin2, uint8_t vbutton);
|
||||
bool Update(Joystick* js);
|
||||
void ReleaseButtons(Joystick* js);
|
||||
|
||||
protected:
|
||||
Encoder* encoder;
|
||||
|
|
70
Joystick.cpp
70
Joystick.cpp
|
@ -1,5 +1,6 @@
|
|||
#include "Joystick.h"
|
||||
#include "Button.h"
|
||||
#include "Reader.h"
|
||||
#include <Mux.h>
|
||||
#include <Arduino.h>
|
||||
#include <stdio.h>
|
||||
|
@ -39,36 +40,16 @@ void Joystick::Init() {
|
|||
delay(100);
|
||||
}
|
||||
|
||||
void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup, Mux* mux, bool analog_only) {
|
||||
Button *button;
|
||||
switch (type) {
|
||||
case BUTTON_PASSTHRU:
|
||||
button = new PassthruButton(pin, _virtual_buttons, pullup, mux, analog_only);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED:
|
||||
button = new PulsedButton(pin, _virtual_buttons, false, false, pullup, mux, analog_only);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED_DOUBLE_ACTION:
|
||||
button = new PulsedButton(pin, _virtual_buttons, true, false, pullup, mux, analog_only);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
|
||||
button = new PulsedButton(pin, _virtual_buttons, true, true, pullup, mux, analog_only);
|
||||
_virtual_buttons += 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
|
||||
_addButton(type, new DirectReader(pin, pullup));
|
||||
}
|
||||
|
||||
_buttons[_num_buttons] = button;
|
||||
_num_buttons++;
|
||||
if (_debug) {
|
||||
char buffer[100];
|
||||
sprintf(buffer, "Added button %d of type %d", _num_buttons - 1, button->type);
|
||||
Serial.println(buffer);
|
||||
}
|
||||
void Joystick::AddMuxButton(uint8_t channel, Mux* mux, ButtonType type, bool pullup) {
|
||||
_addButton(type, new MuxReader(channel, mux, pullup));
|
||||
}
|
||||
|
||||
void Joystick::AddMatrixButton(uint8_t row, uint8_t col, ButtonType type, bool pullup) {
|
||||
_addButton(type, new MatrixReader(row, col, pullup));
|
||||
}
|
||||
|
||||
void Joystick::AddEncoder(uint8_t pin1, uint8_t pin2, ButtonType type) {
|
||||
|
@ -164,3 +145,34 @@ void Joystick::Write() {
|
|||
void Joystick::_UpdateAxis(uint8_t index) {
|
||||
if (_debug) Serial.println("STUB: Joystick::_UpdateAxis");
|
||||
}
|
||||
|
||||
void Joystick::_addButton(ButtonType type, Reader* reader) {
|
||||
switch (type) {
|
||||
case BUTTON_PASSTHRU:
|
||||
button = new PassthruButton(_virtual_buttons, reader);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED:
|
||||
button = new PulsedButton(_virtual_buttons, reader, false, false);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED_DOUBLE_ACTION:
|
||||
button = new PulsedButton(_virtual_buttons, reader, true, false);
|
||||
_virtual_buttons++;
|
||||
break;
|
||||
case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
|
||||
button = new PulsedButton(_virtual_buttons, reader, true, true);
|
||||
_virtual_buttons += 2;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
_buttons[_num_buttons] = button;
|
||||
_num_buttons++;
|
||||
if (_debug) {
|
||||
char buffer[100];
|
||||
sprintf(buffer, "Added button %d of type %d", _num_buttons - 1, button->type);
|
||||
Serial.println(buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ class Joystick {
|
|||
// If `pullup` is false, your button should connect the pin to VCC.
|
||||
// Setting `analogOnly` to true indicates your button *must* be read with analog code, such as the A6 and A7 pins
|
||||
// on the Arduino Nano.
|
||||
void AddButton(uint8_t pin, ButtonType type, bool pullup=true, Mux* mux=NULL, bool analog_only=false);
|
||||
void AddButton(uint8_t pin, ButtonType type, bool pullup=true);
|
||||
void AddMuxButton(uint8_t channel, Mux* mux, ButtonType type, bool pullup=true);
|
||||
void AddMatrixButton(uint8_t row, uint8_t col, ButtonType type, bool pullup=true);
|
||||
|
||||
// Add a rotary encoder. ENCODER button types allow you to treat an encoder as a momentary button or an axis (TODO)
|
||||
void AddEncoder(uint8_t pin1, uint8_t pin2, ButtonType type);
|
||||
|
@ -59,6 +61,8 @@ class Joystick {
|
|||
|
||||
void _UpdateAxis(uint8_t index);
|
||||
|
||||
void _addButton(ButtonType type, Reader* reader);
|
||||
|
||||
Button* _buttons[JOYSTICK_NUM_BUTTONS];
|
||||
uint8_t _num_buttons;
|
||||
uint8_t _virtual_buttons; // a single user-defined button can have multiple virtual buttons.
|
||||
|
|
61
Reader.cpp
Normal file
61
Reader.cpp
Normal file
|
@ -0,0 +1,61 @@
|
|||
#include "Reader.h"
|
||||
|
||||
#include <Mux.h>
|
||||
#include <Bounce2.h>
|
||||
|
||||
|
||||
Reader::Reader(bool inverted) {
|
||||
this->inverted = inverted;
|
||||
}
|
||||
|
||||
bool Reader::On() {
|
||||
bool state = bouncer.rose();
|
||||
if (inverted) state = bouncer.fell();
|
||||
return state;
|
||||
}
|
||||
|
||||
uint8_t Reader::getMode(bool pullup) {
|
||||
if (pullup) return INPUT_PULLUP;
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
|
||||
DirectReader::DirectReader(uint8_t pin, bool inverted) : Reader(inverted) {
|
||||
uint8_t mode = getMode(inverted);
|
||||
this->bouncer.attach(pin)
|
||||
}
|
||||
|
||||
bool DirectReader::Update() {
|
||||
return bouncer.update();
|
||||
}
|
||||
|
||||
|
||||
MuxReader::MuxReader(uint8_t channel, Mux* mux, bool inverted) : Reader(inverted) {
|
||||
uint8_t mode = getMode(inverted);
|
||||
this->bouncer.attach(mux->signalPin().pin, mode);
|
||||
this->channel = channel;
|
||||
}
|
||||
|
||||
bool MuxReader::Update() {
|
||||
mux->channel(channel);
|
||||
return bouncer.update();
|
||||
}
|
||||
|
||||
|
||||
MatrixReader::MatrixReader(uint8_t row, uint8_t col, bool inverted) : Reader(inverted) {
|
||||
uint8_t mode = getMode(inverted);
|
||||
this->bouncer.attach(row, mode);
|
||||
this->col = col;
|
||||
}
|
||||
|
||||
bool MatrixReader::Update() {
|
||||
digitalWrite(col, LOW);
|
||||
delayMicroseconds(10);
|
||||
|
||||
bool changed = bouncer.update();
|
||||
|
||||
digitalWrite(col, HIGH);
|
||||
delayMicroseconds(10);
|
||||
|
||||
return changed;
|
||||
}
|
59
Reader.h
Normal file
59
Reader.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
// "Readers" represent different methods for reading the state of a pin.
|
||||
// They also include debouncing logic using the Bounce2 library, when appropriate.
|
||||
|
||||
#ifndef _READER_H_
|
||||
#define _READER_H_
|
||||
|
||||
#include <Bounce2.h>
|
||||
#include <Mux.h>
|
||||
|
||||
// The abstract base class - a very simple interface
|
||||
class Reader {
|
||||
public:
|
||||
Reader(bool inverted);
|
||||
|
||||
virtual bool Update() = 0; // should return true if the state of the pin has changed
|
||||
bool On();
|
||||
|
||||
protected:
|
||||
uint8_t getMode(bool pullup);
|
||||
|
||||
Bounce bouncer;
|
||||
bool inverted;
|
||||
};
|
||||
|
||||
|
||||
// A standard reader; the button is connected directly to a switch
|
||||
class DirectReader {
|
||||
public:
|
||||
DirectReader(uint8_t pin, bool inverted = true);
|
||||
bool Update();
|
||||
bool On();
|
||||
};
|
||||
|
||||
|
||||
// The button is connected to a Multiplexer channel
|
||||
class MuxReader {
|
||||
public:
|
||||
MuxReader(uint8_t channel, Mux* mux, bool inverted = true);
|
||||
bool Update();
|
||||
bool On();
|
||||
|
||||
protected:
|
||||
Mux * mux;
|
||||
};
|
||||
|
||||
|
||||
// The button is connected via a scan matrix
|
||||
// "row" should always be the input, with "col" the selecter.
|
||||
class MatrixReader {
|
||||
public:
|
||||
MatrixReader(uint8_t row, uint8_t col, bool inverted = true);
|
||||
bool Update();
|
||||
bool On();
|
||||
|
||||
protected:
|
||||
uint8_t col;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user