Refactor code substantially, moving buttons into separate classes and using a lot more pointers to conserve memory until it is needed.
This commit is contained in:
parent
346e612f65
commit
a69c2d3364
132
Button.cpp
Normal file
132
Button.cpp
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#include "Button.h"
|
||||||
|
#include "Joystick.h"
|
||||||
|
#include <Encoder.h>
|
||||||
|
#include <Mux.h>
|
||||||
|
|
||||||
|
using namespace admux;
|
||||||
|
|
||||||
|
Button::Button(uint8_t vbutton) {
|
||||||
|
this->vbutton = vbutton;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::ReleaseButtons(Joystick* js) {
|
||||||
|
js->ReleaseButton(vbutton);
|
||||||
|
}
|
||||||
|
|
||||||
|
SwitchButton::SwitchButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux) : 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
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) : SwitchButton(pin, vbutton, pullup, mux) {
|
||||||
|
this->type = BUTTON_PASSTHRU;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PassthruButton::Update(Joystick* js) {
|
||||||
|
if (!BouncerUpdate()) return;
|
||||||
|
if (On()) js->PressButton(vbutton);
|
||||||
|
else js->ReleaseButton(vbutton);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
LatchedButton::LatchedButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux) : SwitchButton(pin, vbutton, pullup, mux) {
|
||||||
|
this->type = BUTTON_LATCHED_MOMENTARY;
|
||||||
|
this->pressed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LatchedButton::Update(Joystick* js) {
|
||||||
|
if (!BouncerUpdate()) return;
|
||||||
|
|
||||||
|
if (On()) {
|
||||||
|
if (!pressed) {
|
||||||
|
js->PressButton(vbutton);
|
||||||
|
pressed = true;
|
||||||
|
} else {
|
||||||
|
js->ReleaseButton(vbutton);
|
||||||
|
pressed = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PulsedButton::PulsedButton(uint8_t pin, uint8_t vbutton, bool double_action, bool split, bool pullup, Mux* mux) : SwitchButton(pin, vbutton, pullup, mux) {
|
||||||
|
if (double_action) {
|
||||||
|
if (split) {
|
||||||
|
this->type = BUTTON_PULSED_DOUBLE_ACTION_SPLIT;
|
||||||
|
this->vbutton2 = vbutton + 1;
|
||||||
|
} else {
|
||||||
|
this->type = BUTTON_PULSED_DOUBLE_ACTION;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this->type = BUTTON_PULSED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PulsedButton::Update(Joystick* js) {
|
||||||
|
if (!BouncerUpdate()) return;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case BUTTON_PULSED:
|
||||||
|
if (On()) js->PressButton(vbutton);
|
||||||
|
break;
|
||||||
|
case BUTTON_PULSED_DOUBLE_ACTION:
|
||||||
|
js->PressButton(vbutton);
|
||||||
|
break;
|
||||||
|
case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
|
||||||
|
if (On()) js->PressButton(vbutton);
|
||||||
|
else js->PressButton(vbutton2);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
this->vbutton2 = vbutton + 1;
|
||||||
|
this->encoder = new Encoder(pin1, pin2);
|
||||||
|
this->last_value = encoder->read();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncoderButton::Update(Joystick* js) {
|
||||||
|
long new_value = encoder->read();
|
||||||
|
if (new_value > last_value) js->PressButton(vbutton);
|
||||||
|
else if (new_value < last_value) js->PressButton(vbutton2);
|
||||||
|
last_value = new_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EncoderButton::ReleaseButtons(Joystick* js) {
|
||||||
|
Button::ReleaseButtons(js);
|
||||||
|
js->ReleaseButton(vbutton2);
|
||||||
|
}
|
97
Button.h
Normal file
97
Button.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
#ifndef _BUTTON_H_
|
||||||
|
#define _BUTTON_H_
|
||||||
|
|
||||||
|
#include <Encoder.h>
|
||||||
|
#include <Mux.h>
|
||||||
|
#include <Bounce2.h>
|
||||||
|
|
||||||
|
using namespace admux;
|
||||||
|
|
||||||
|
class Joystick; // forward declaration
|
||||||
|
|
||||||
|
enum ButtonType {
|
||||||
|
BUTTON_PASSTHRU = 0x1, // always use the (debounced) absolute state of the input
|
||||||
|
BUTTON_PULSED = 0x2, // on button press, send an on signal followed immediately by an off signal.
|
||||||
|
BUTTON_PULSED_DOUBLE_ACTION = 0x4, // Send a button press twice - once for press and once for release.
|
||||||
|
BUTTON_PULSED_DOUBLE_ACTION_SPLIT = 0x8, // Send two separate button presses - one button on press, another on release.
|
||||||
|
BUTTON_LATCHED_MOMENTARY = 0x10,
|
||||||
|
ENCODER_PULSED_SPLIT = 0x20 // A rotary encoder that should be treated as two different pulsed/momentary buttons, one for each direction
|
||||||
|
};
|
||||||
|
|
||||||
|
// The abstract button base class. A button must have, at a minimum:
|
||||||
|
// * a button *type* (typically automatically assigned by the constructor)
|
||||||
|
// * at least one "virtual button" - that is, a Joystick input that it controls
|
||||||
|
// * an update method.
|
||||||
|
class Button {
|
||||||
|
public:
|
||||||
|
Button(uint8_t vbutton);
|
||||||
|
virtual void Update(Joystick* js) = 0;
|
||||||
|
virtual void ReleaseButtons(Joystick* js);
|
||||||
|
ButtonType type;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
uint8_t vbutton;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 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 {
|
||||||
|
public:
|
||||||
|
SwitchButton(uint8_t pin, uint8_t vbutton, bool pullup, Mux* mux);
|
||||||
|
virtual void Update(Joystick* js) = 0;
|
||||||
|
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);
|
||||||
|
void Update(Joystick* js);
|
||||||
|
};
|
||||||
|
|
||||||
|
class LatchedButton : public SwitchButton {
|
||||||
|
public:
|
||||||
|
LatchedButton(uint8_t pin, uint8_t vbutton, bool pullup = true, Mux* mux = NULL);
|
||||||
|
void Update(Joystick* js);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool pressed;
|
||||||
|
};
|
||||||
|
|
||||||
|
class PulsedButton : public SwitchButton {
|
||||||
|
public:
|
||||||
|
PulsedButton(uint8_t pin, uint8_t vbutton, bool double_action = false, bool split = false, bool pullup = true, Mux* mux = NULL);
|
||||||
|
void Update(Joystick* js);
|
||||||
|
void ReleaseButtons(Joystick* js);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool double_action;
|
||||||
|
bool split;
|
||||||
|
uint8_t vbutton2;
|
||||||
|
};
|
||||||
|
|
||||||
|
class EncoderButton : public Button {
|
||||||
|
public:
|
||||||
|
EncoderButton(uint8_t pin1, uint8_t pin2, uint8_t vbutton);
|
||||||
|
void Update(Joystick* js);
|
||||||
|
void ReleaseButtons(Joystick* js);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Encoder* encoder;
|
||||||
|
long last_value;
|
||||||
|
uint8_t vbutton2;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal use only.
|
||||||
|
#define _BUTTON_PULSED_TYPES (BUTTON_PULSED | BUTTON_PULSED_DOUBLE_ACTION | BUTTON_PULSED_DOUBLE_ACTION_SPLIT | ENCODER_PULSED_SPLIT)
|
||||||
|
|
||||||
|
#endif
|
152
Joystick.cpp
152
Joystick.cpp
|
@ -1,4 +1,5 @@
|
||||||
#include "Joystick.h"
|
#include "Joystick.h"
|
||||||
|
#include "Button.h"
|
||||||
#include <Mux.h>
|
#include <Mux.h>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
@ -22,7 +23,6 @@ Joystick::Joystick(bool debug) {
|
||||||
_debug = debug;
|
_debug = debug;
|
||||||
_virtual_buttons = 0;
|
_virtual_buttons = 0;
|
||||||
_num_axes = 0;
|
_num_axes = 0;
|
||||||
_num_mux = 0;
|
|
||||||
_num_buttons = 0;
|
_num_buttons = 0;
|
||||||
_have_pulsed_button = false;
|
_have_pulsed_button = false;
|
||||||
|
|
||||||
|
@ -39,21 +39,39 @@ void Joystick::Init() {
|
||||||
delay(100);
|
delay(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup) {
|
void Joystick::AddButton(uint8_t pin, ButtonType type, bool pullup, Mux* mux) {
|
||||||
_BuildButton(pin, type, pullup);
|
Button *button;
|
||||||
|
switch (type) {
|
||||||
|
case BUTTON_PASSTHRU:
|
||||||
|
button = new PassthruButton(pin, _virtual_buttons, pullup, mux);
|
||||||
|
_virtual_buttons++;
|
||||||
|
case BUTTON_PULSED:
|
||||||
|
button = new PulsedButton(pin, _virtual_buttons, false, false, pullup, mux);
|
||||||
|
_virtual_buttons++;
|
||||||
|
case BUTTON_PULSED_DOUBLE_ACTION:
|
||||||
|
button = new PulsedButton(pin, _virtual_buttons, true, false, pullup, mux);
|
||||||
|
_virtual_buttons++;
|
||||||
|
case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
|
||||||
|
button = new PulsedButton(pin, _virtual_buttons, true, true, pullup, mux);
|
||||||
|
_virtual_buttons += 2;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_buttons[_num_buttons] = button;
|
||||||
|
_num_buttons++;
|
||||||
|
if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::AddEncoder(uint8_t pin0, uint8_t pin1, ButtonType type, bool pullup) {
|
void Joystick::AddEncoder(uint8_t pin1, uint8_t pin2, ButtonType type) {
|
||||||
|
Button *button;
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ENCODER_PULSED_SPLIT:
|
case ENCODER_PULSED_SPLIT:
|
||||||
// add an encoder button. _BuildButton() doesn't do everything we need, however...
|
// add an encoder button. _BuildButton() doesn't do everything we need, however...
|
||||||
Button *button = _BuildButton(pin0, type, pullup);
|
button = new EncoderButton(pin1, pin2, _virtual_buttons);
|
||||||
|
_buttons[_num_buttons] = button;
|
||||||
// ... so we set up the encoder stuff here. button->pin and button->bouncer will be
|
_num_buttons++;
|
||||||
// ignored
|
_virtual_buttons += 2;
|
||||||
button->encoder_button = true;
|
|
||||||
button->encoder = new Encoder(pin0, pin1);
|
|
||||||
long last_enc = button->encoder->read();
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (_debug) {
|
if (_debug) {
|
||||||
|
@ -63,70 +81,19 @@ void Joystick::AddEncoder(uint8_t pin0, uint8_t pin1, ButtonType type, bool pull
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Joystick::AddMuxButton(uint8_t mux_id, uint8_t mux_channel, ButtonType type, bool pullup) {
|
|
||||||
uint8_t pin = _mux[mux_id]->signalPin().pin;
|
|
||||||
Button *button = _BuildButton(pin, type, pullup);
|
|
||||||
button->mux = true;
|
|
||||||
button->mux_id = mux_id;
|
|
||||||
button->mux_channel = mux_channel;
|
|
||||||
}
|
|
||||||
|
|
||||||
Button* Joystick::_BuildButton(uint8_t pin, ButtonType type, bool pullup) {
|
|
||||||
uint8_t mode;
|
|
||||||
if (pullup) mode = INPUT_PULLUP;
|
|
||||||
else mode = INPUT;
|
|
||||||
|
|
||||||
Button button;
|
|
||||||
button.type = type;
|
|
||||||
button.inverted = pullup;
|
|
||||||
button.bouncer.attach(pin, mode);
|
|
||||||
uint8_t increment = 1;
|
|
||||||
button.vbutton0 = _virtual_buttons;
|
|
||||||
|
|
||||||
if (type & (BUTTON_PULSED_DOUBLE_ACTION_SPLIT | ENCODER_PULSED_SPLIT)) {
|
|
||||||
increment = 2;
|
|
||||||
button.vbutton1 = _virtual_buttons + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_virtual_buttons + increment > JOYSTICK_NUM_BUTTONS) {
|
|
||||||
// todo: fail here
|
|
||||||
}
|
|
||||||
|
|
||||||
_buttons[_num_buttons] = button;
|
|
||||||
_num_buttons++;
|
|
||||||
_virtual_buttons += increment;
|
|
||||||
|
|
||||||
if (type & _BUTTON_PULSED_TYPES) _have_pulsed_button = true;
|
|
||||||
|
|
||||||
return &button;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Joystick::AddAxis(uint8_t pin) {
|
void Joystick::AddAxis(uint8_t pin) {
|
||||||
_axes[_num_axes] = pin;
|
_axes[_num_axes] = pin;
|
||||||
_num_axes++;
|
_num_axes++;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Joystick::AddMux(uint8_t signal_pin, Pinset addr_pins, bool pullup) {
|
|
||||||
uint8_t mux_id = _num_mux;
|
|
||||||
uint8_t mode = INPUT_PULLUP;
|
|
||||||
if (!pullup) mode = INPUT;
|
|
||||||
Mux mux(Pin(signal_pin, mode, PinType::Digital), addr_pins);
|
|
||||||
_mux[mux_id] = &mux;
|
|
||||||
_num_mux++;
|
|
||||||
return mux_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Joystick::Update() {
|
void Joystick::Update() {
|
||||||
JoyReport oldReport = _joyReport;
|
JoyReport oldReport = _joyReport;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < _num_buttons; i++) {
|
for (uint8_t i = 0; i < _num_buttons; i++) {
|
||||||
if (_buttons[i].type == ENCODER_PULSED_SPLIT) { // todo: make this check for any encoder type
|
_buttons[i]->Update(this);
|
||||||
_UpdateEncoder(i);
|
|
||||||
} else {
|
|
||||||
_UpdateButton(i);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: implement this and also refactor it into a class or classes
|
||||||
for (uint8_t i = 0; i < _num_axes; i++) {
|
for (uint8_t i = 0; i < _num_axes; i++) {
|
||||||
_UpdateAxis(i);
|
_UpdateAxis(i);
|
||||||
}
|
}
|
||||||
|
@ -167,9 +134,8 @@ void Joystick::ReleaseAllButtons() {
|
||||||
|
|
||||||
void Joystick::_ReleasePulsedButtons() {
|
void Joystick::_ReleasePulsedButtons() {
|
||||||
for (uint8_t i = 0; i < _num_buttons; i++ ) {
|
for (uint8_t i = 0; i < _num_buttons; i++ ) {
|
||||||
Button button = _buttons[i];
|
Button* button = _buttons[i];
|
||||||
if (button.type & _BUTTON_PULSED_TYPES) ReleaseButton(button.vbutton0);
|
if (button->type & _BUTTON_PULSED_TYPES) button->ReleaseButtons(this);
|
||||||
if (button.type & BUTTON_PULSED_DOUBLE_ACTION_SPLIT) ReleaseButton(button.vbutton1);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,59 +158,7 @@ void Joystick::Write() {
|
||||||
delay(250);
|
delay(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: bite the bullet and use inheritance here, this is getting out of hand
|
|
||||||
void Joystick::_UpdateButton(uint8_t button_num) {
|
|
||||||
Button *button = &_buttons[button_num];
|
|
||||||
if (button->mux) {
|
|
||||||
_mux[button->mux_id]->channel(button->mux_channel);
|
|
||||||
}
|
|
||||||
bool changed = button->bouncer.update();
|
|
||||||
if (!changed) return;
|
|
||||||
|
|
||||||
bool on = button->bouncer.rose();
|
|
||||||
if (button->inverted) on = button->bouncer.fell();
|
|
||||||
|
|
||||||
switch (button->type) {
|
|
||||||
case BUTTON_PASSTHRU:
|
|
||||||
if (on) PressButton(button->vbutton0);
|
|
||||||
else ReleaseButton(button->vbutton0);
|
|
||||||
break;
|
|
||||||
case BUTTON_PULSED:
|
|
||||||
if (on) PressButton(button->vbutton0);
|
|
||||||
break;
|
|
||||||
case BUTTON_PULSED_DOUBLE_ACTION:
|
|
||||||
PressButton(button->vbutton0);
|
|
||||||
break;
|
|
||||||
case BUTTON_PULSED_DOUBLE_ACTION_SPLIT:
|
|
||||||
if (on) PressButton(button->vbutton0);
|
|
||||||
else PressButton(button->vbutton1);
|
|
||||||
break;
|
|
||||||
case BUTTON_LATCHED_MOMENTARY:
|
|
||||||
if (on) {
|
|
||||||
if (!button->pressed) {
|
|
||||||
PressButton(button->vbutton0);
|
|
||||||
button->pressed = true;
|
|
||||||
} else {
|
|
||||||
ReleaseButton(button->vbutton0);
|
|
||||||
button->pressed = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
if (_debug) {
|
|
||||||
Serial.print("DEBUG: Unhandled button type: ");
|
|
||||||
Serial.println(button->type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Joystick::_UpdateEncoder(uint8_t index) {
|
|
||||||
Button *button = &_buttons[index];
|
|
||||||
long new_value = button->encoder->read();
|
|
||||||
if (new_value > button->last_enc) PressButton(button->vbutton0);
|
|
||||||
else if (new_value < button->last_enc) PressButton(button->vbutton1);
|
|
||||||
button->last_enc = new_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Joystick::_UpdateAxis(uint8_t index) {
|
void Joystick::_UpdateAxis(uint8_t index) {
|
||||||
if (_debug) Serial.println("STUB: Joystick::_UpdateAxis");
|
if (_debug) Serial.println("STUB: Joystick::_UpdateAxis");
|
||||||
|
|
61
Joystick.h
61
Joystick.h
|
@ -1,6 +1,7 @@
|
||||||
#ifndef _JOYSTICK_H_
|
#ifndef _JOYSTICK_H_
|
||||||
#define _JOYSTICK_H_
|
#define _JOYSTICK_H_
|
||||||
|
|
||||||
|
#include "Button.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Bounce2.h>
|
#include <Bounce2.h>
|
||||||
#include <Encoder.h>
|
#include <Encoder.h>
|
||||||
|
@ -19,44 +20,11 @@ using namespace admux;
|
||||||
#endif
|
#endif
|
||||||
#define JOYSTICK_NUM_BYTES (JOYSTICK_NUM_BUTTONS+7)/8
|
#define JOYSTICK_NUM_BYTES (JOYSTICK_NUM_BUTTONS+7)/8
|
||||||
|
|
||||||
#ifndef MAX_MUX
|
|
||||||
#define MAX_MUX 3
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum ButtonType {
|
|
||||||
BUTTON_PASSTHRU = 0x1, // always use the (debounced) absolute state of the input
|
|
||||||
BUTTON_PULSED = 0x2, // on button press, send an on signal followed immediately by an off signal.
|
|
||||||
BUTTON_PULSED_DOUBLE_ACTION = 0x4, // Send a button press twice - once for press and once for release.
|
|
||||||
BUTTON_PULSED_DOUBLE_ACTION_SPLIT = 0x8, // Send two separate button presses - one button on press, another on release.
|
|
||||||
BUTTON_LATCHED_MOMENTARY = 0x10,
|
|
||||||
ENCODER_PULSED_SPLIT = 0x20 // A rotary encoder that should be treated as two different pulsed/momentary buttons, one for each direction
|
|
||||||
};
|
|
||||||
|
|
||||||
struct JoyReport {
|
struct JoyReport {
|
||||||
int16_t axis[JOYSTICK_NUM_AXES];
|
int16_t axis[JOYSTICK_NUM_AXES];
|
||||||
uint8_t button[JOYSTICK_NUM_BYTES];
|
uint8_t button[JOYSTICK_NUM_BYTES];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Button {
|
|
||||||
ButtonType type;
|
|
||||||
Bounce bouncer;
|
|
||||||
uint8_t vbutton0;
|
|
||||||
uint8_t vbutton1; // only used by BUTTON_PULSED_DOUBLE_ACTION_SPLIT
|
|
||||||
bool pressed = false; // only used by BUTTON_LATCHED_MOMENTARY
|
|
||||||
bool inverted = false; // if true, send button press on release and vice versa.
|
|
||||||
|
|
||||||
// multiplexer button settings
|
|
||||||
// todo: this should probably be abstracted out from this struct...
|
|
||||||
bool mux;
|
|
||||||
uint8_t mux_id;
|
|
||||||
uint8_t mux_channel;
|
|
||||||
|
|
||||||
// encoder button settings
|
|
||||||
bool encoder_button;
|
|
||||||
Encoder* encoder;
|
|
||||||
long last_enc;
|
|
||||||
};
|
|
||||||
|
|
||||||
bool operator ==(JoyReport a, JoyReport b);
|
bool operator ==(JoyReport a, JoyReport b);
|
||||||
bool operator !=(JoyReport a, JoyReport b);
|
bool operator !=(JoyReport a, JoyReport b);
|
||||||
|
|
||||||
|
@ -70,35 +38,26 @@ class Joystick {
|
||||||
// Button types are documented in the ButtonType enum.
|
// Button types are documented in the ButtonType enum.
|
||||||
// If `pullup` is true, your button should connect the pin to ground. (also be sure that your board supports INPUT_PULLUP on that pin)
|
// If `pullup` is true, your button should connect the pin to ground. (also be sure that your board supports INPUT_PULLUP on that pin)
|
||||||
// If `pullup` is false, your button should connect the pin to VCC.
|
// If `pullup` is false, your button should connect the pin to VCC.
|
||||||
// Mux parameters are ignored unless `mux` is true.
|
void AddButton(uint8_t pin, ButtonType type, bool pullup=true, Mux* mux=NULL);
|
||||||
void AddButton(uint8_t pin, 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)
|
// 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 pin0, uint8_t pin1, ButtonType type, bool pullup=true);
|
void AddEncoder(uint8_t pin1, uint8_t pin2, ButtonType type);
|
||||||
void AddMuxButton(uint8_t mux_id, uint8_t mux_channel, ButtonType type, bool pullup=true);
|
|
||||||
|
|
||||||
// Add an analog axis to the joystick. THIS METHOD IS NOT CURRENTLY TESTED OR SUPPORTED. It might work, but probably not.
|
// Add an analog axis to the joystick. THIS METHOD IS NOT CURRENTLY TESTED OR SUPPORTED. It might work, but probably not.
|
||||||
void AddAxis(uint8_t pin);
|
void AddAxis(uint8_t pin);
|
||||||
|
|
||||||
// Add control for a multiplexer. To add a button that's connected via the multiplexer,
|
void PressButton(uint8_t button);
|
||||||
// pass the mux's signal pin as the pin parameter to AddButton(), along with the mux* parameters.
|
void ReleaseButton(uint8_t button);
|
||||||
// mux_id is the array index of the mux (in the order you added them via AddMux())
|
|
||||||
uint8_t AddMux(uint8_t signal_pin, Pinset addr_pins, bool pullup=true);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetAxis(uint8_t axis, int16_t value);
|
void SetAxis(uint8_t axis, int16_t value);
|
||||||
void PressButton(uint8_t button);
|
|
||||||
void ReleaseButton(uint8_t button);
|
|
||||||
void ReleaseAllButtons();
|
void ReleaseAllButtons();
|
||||||
void Write();
|
void Write();
|
||||||
|
|
||||||
void _ReleasePulsedButtons();
|
void _ReleasePulsedButtons();
|
||||||
void _UpdateButton(uint8_t index);
|
|
||||||
void _UpdateEncoder(uint8_t index);
|
|
||||||
void _UpdateAxis(uint8_t index);
|
void _UpdateAxis(uint8_t index);
|
||||||
|
|
||||||
Button* _BuildButton(uint8_t pin, ButtonType type, bool pullup);
|
Button* _buttons[JOYSTICK_NUM_BUTTONS];
|
||||||
|
|
||||||
Button _buttons[JOYSTICK_NUM_BUTTONS];
|
|
||||||
uint8_t _num_buttons;
|
uint8_t _num_buttons;
|
||||||
uint8_t _virtual_buttons; // a single user-defined button can have multiple virtual buttons.
|
uint8_t _virtual_buttons; // a single user-defined button can have multiple virtual buttons.
|
||||||
bool _have_pulsed_button;
|
bool _have_pulsed_button;
|
||||||
|
@ -108,12 +67,6 @@ class Joystick {
|
||||||
|
|
||||||
JoyReport _joyReport;
|
JoyReport _joyReport;
|
||||||
bool _debug;
|
bool _debug;
|
||||||
|
|
||||||
Mux *_mux[MAX_MUX];
|
|
||||||
uint8_t _num_mux;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Internal use only.
|
|
||||||
#define _BUTTON_PULSED_TYPES (BUTTON_PULSED | BUTTON_PULSED_DOUBLE_ACTION | BUTTON_PULSED_DOUBLE_ACTION_SPLIT | ENCODER_PULSED_SPLIT)
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <Joystick.h>
|
#include <Joystick.h>
|
||||||
#include <Mux.h>
|
#include <Mux.h>
|
||||||
|
|
||||||
using admux::Pinset;
|
using namespace admux;
|
||||||
|
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
Joystick joystick(debug);
|
Joystick joystick(debug);
|
||||||
|
@ -26,7 +26,9 @@ void setup() {
|
||||||
Pinset addr_pins = Pinset(10, 11, 12, 13);
|
Pinset addr_pins = Pinset(10, 11, 12, 13);
|
||||||
uint8_t mux_id = joystick.AddMux(9, addr_pins);
|
uint8_t mux_id = joystick.AddMux(9, addr_pins);
|
||||||
|
|
||||||
joystick.AddMuxButton(mux_id, 0, BUTTON_PASSTHRU);
|
Mux* mux = new Mux(Pin(9, INPUT_PULLUP, PinType::Digital), Pinset(10, 11, 12, 13));
|
||||||
|
|
||||||
|
joystick.AddButton(0, BUTTON_PASSTHRU, true, mux);
|
||||||
|
|
||||||
// start up serial communication
|
// start up serial communication
|
||||||
joystick.Init();
|
joystick.Init();
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
#include <Joystick.h>
|
#include <Joystick.h>
|
||||||
#include <Mux.h>
|
#include <Mux.h>
|
||||||
|
|
||||||
|
using namespace admux;
|
||||||
|
|
||||||
bool debug = false;
|
bool debug = false;
|
||||||
Joystick joystick(debug);
|
Joystick joystick(debug);
|
||||||
|
|
||||||
|
@ -29,17 +31,17 @@ void setup() {
|
||||||
joystick.AddButton(A0, BUTTON_PASSTHRU);
|
joystick.AddButton(A0, BUTTON_PASSTHRU);
|
||||||
|
|
||||||
// to get more room for our inputs, we add an 8-bit multiplexer
|
// to get more room for our inputs, we add an 8-bit multiplexer
|
||||||
uint8_t mux = joystick.AddMux(A1, admux::Pinset(A2, A3, A4, A5), 4);
|
Mux* mux = new Mux(Pin(A1, INPUT_PULLUP, PinType::Digital), Pinset(A2, A3, A4, A5));
|
||||||
|
|
||||||
// now we can add the rest of the buttons
|
// now we can add the rest of the buttons
|
||||||
joystick.AddMuxButton(mux, 0, BUTTON_PASSTHRU);
|
joystick.AddButton(0, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 1, BUTTON_PASSTHRU);
|
joystick.AddButton(1, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 2, BUTTON_PASSTHRU);
|
joystick.AddButton(2, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 3, BUTTON_PASSTHRU);
|
joystick.AddButton(3, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 4, BUTTON_PASSTHRU);
|
joystick.AddButton(4, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 5, BUTTON_PASSTHRU);
|
joystick.AddButton(5, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 6, BUTTON_PASSTHRU);
|
joystick.AddButton(6, BUTTON_PASSTHRU, true, mux);
|
||||||
joystick.AddMuxButton(mux, 7, BUTTON_PASSTHRU);
|
joystick.AddButton(7, BUTTON_PASSTHRU, true, mux);
|
||||||
|
|
||||||
joystick.Init();
|
joystick.Init();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user