Skip to content

Commit

Permalink
Replace RotaryNavConfig with RotaryInputAdapter (#206)
Browse files Browse the repository at this point in the history
Replaced the RotaryNavConfig struct with a new RotaryInputAdapter class to handle rotary input for LCD menus efficiently. The adapter manages user input through a rotary encoder, recognizing short, long, and double presses for menu navigation and selection.
  • Loading branch information
forntoh authored Sep 17, 2024
1 parent 244a5dd commit afeaf80
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 92 deletions.
18 changes: 5 additions & 13 deletions examples/InputRotary/InputRotary.ino
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
#include <ItemSubMenu.h>
#include <LcdMenu.h>
#include <SimpleRotary.h>
#include <input/SimpleRotaryAdapter.h>
#include <interface/LiquidCrystalI2CAdapter.h>
#include <utils/RotaryNavConfig.h>

#define LCD_ROWS 2
#define LCD_COLS 16
Expand All @@ -31,26 +31,18 @@ SUB_MENU(
ITEM_INPUT_CHARSET("User", charset, inputCallback),
ITEM_COMMAND("Clear", clearInput));

LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);

SimpleRotary encoder(2, 3, 4);

RotaryNavConfig menuConfig = {
.encoder = &encoder,
.menu = &menu,
.longPressDuration = 1000,
};
LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);
SimpleRotaryAdapter rotaryInput(&menu, &encoder);

void setup() {
Serial.begin(9600);
menu.initialize(mainMenu);
}

void loop() {
// Call the handleRotaryMenu function, passing the menuConfig instance
processWithRotaryEncoder(&menuConfig);
}
void loop() { rotaryInput.observe(); }

// Define the callbacks
void inputCallback(char* value) {
Expand Down
19 changes: 5 additions & 14 deletions examples/SimpleRotary/SimpleRotary.ino
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
#include <ItemToggle.h>
#include <LcdMenu.h>
#include <SimpleRotary.h>
#include <input/SimpleRotaryAdapter.h>
#include <interface/LiquidCrystalI2CAdapter.h>
#include <utils/RotaryNavConfig.h>

#define LCD_ROWS 2
#define LCD_COLS 16
Expand Down Expand Up @@ -32,27 +32,18 @@ MAIN_MENU(
ITEM_TOGGLE("Backlight", toggleBacklight),
ITEM_BASIC("Blink random"));

LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);

SimpleRotary encoder(2, 3, 4);

RotaryNavConfig menuConfig = {
.encoder = &encoder,
.menu = &menu,
.longPressDuration = 1000,
.doublePressThreshold = 500,
};
LiquidCrystalI2CAdapter lcdAdapter(0x27, LCD_COLS, LCD_ROWS);
LcdMenu menu(lcdAdapter);
SimpleRotaryAdapter rotaryInput(&menu, &encoder);

void setup() {
Serial.begin(9600);
menu.initialize(mainMenu);
}

void loop() {
// Call the handleRotaryMenu function, passing the menuConfig instance
processWithRotaryEncoder(&menuConfig);
}
void loop() { rotaryInput.observe(); }

// Define the callbacks
void toggleBacklight(uint16_t isOn) {
Expand Down
71 changes: 71 additions & 0 deletions src/input/SimpleRotaryAdapter.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include "InputInterface.h"
#include <SimpleRotary.h>

/**
* @class SimpleRotaryAdapter
* @brief Adapter for handling rotary input for an LCD menu.
*
* This class interfaces with a rotary encoder to manage user input
* for navigating and selecting options in an LCD menu.
*
* It processes rotary encoder rotations to navigate through menu options
* and handles button presses for various actions, including:
* - Short press for selecting an option
* - Long press for going back
* - Double press for backspacing
*
* The values for long press duration (defined as LONG_PRESS_DURATION) and
* double press threshold (defined as DOUBLE_PRESS_THRESHOLD) can be
* overwritten by defining new ones with #define.
*
* @param menu Pointer to the LcdMenu instance that this adapter will control.
* @param encoder Pointer to the SimpleRotary instance representing the rotary encoder.
*/
class SimpleRotaryAdapter : public InputInterface {
private:
unsigned long lastPressTime = 0; // Last time the button was pressed
bool pendingEnter = false; // Flag to indicate if an enter action is pending
SimpleRotary* encoder; // Pointer to the SimpleRotary instance

public:
SimpleRotaryAdapter(LcdMenu* menu, SimpleRotary* encoder)
: InputInterface(menu), encoder(encoder) {
}

void observe() override {
// Handle rotary encoder rotation
uint8_t rotation = encoder->rotate();
if (rotation == 1) {
menu->process(DOWN); // Call DOWN action
} else if (rotation == 2) {
menu->process(UP); // Call UP action
}

// Handle button press (short, long, and double press)
uint8_t pressType = encoder->pushType(LONG_PRESS_DURATION);
unsigned long currentTime = millis();

if (pressType == 1) {
if (pendingEnter) {
if (DOUBLE_PRESS_THRESHOLD > 0 && currentTime - lastPressTime < DOUBLE_PRESS_THRESHOLD) {
menu->process(BACKSPACE); // Call BACKSPACE action (double press)
pendingEnter = false;
}
} else {
pendingEnter = true;
lastPressTime = currentTime;
}
} else if (pressType == 2) {
menu->process(BACK); // Call BACK action (long press)
pendingEnter = false;
}

// Check if the doublePressThreshold has elapsed for pending enter action
if ((!menu->lcd.getEditModeEnabled() && pendingEnter) || (pendingEnter && (currentTime - lastPressTime >= DOUBLE_PRESS_THRESHOLD))) {
menu->process(ENTER); // Call ENTER action (short press)
pendingEnter = false;
}
}
};
65 changes: 0 additions & 65 deletions src/utils/RotaryNavConfig.h

This file was deleted.

9 changes: 9 additions & 0 deletions src/utils/constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,15 @@ const byte MENU_ITEM_PROGRESS = 10;
#define LEFT 131 // >127
#define CLEAR 132 // >127
//
// Rotary encoder configuration
//
#ifndef LONG_PRESS_DURATION
#define LONG_PRESS_DURATION 1000
#endif
#ifndef DOUBLE_PRESS_THRESHOLD
#define DOUBLE_PRESS_THRESHOLD 300
#endif
//
const byte DOWN_ARROW[8] = {
0b00100, // *
0b00100, // *
Expand Down

0 comments on commit afeaf80

Please sign in to comment.