-
Notifications
You must be signed in to change notification settings - Fork 942
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into miltieIV2/add_support_for_adafruit_feather…
…_rp2040_rfm95
- Loading branch information
Showing
17 changed files
with
399 additions
and
39 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -224,7 +224,6 @@ int32_t ButtonThread::runOnce() | |
btnEvent = BUTTON_EVENT_NONE; | ||
} | ||
|
||
runASAP = false; | ||
return 50; | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,260 @@ | ||
|
||
#include "ExpressLRSFiveWay.h" | ||
|
||
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE | ||
|
||
static const char inputSourceName[] = "ExpressLRS5Way"; // should match "allow input source" string | ||
|
||
/** | ||
* @brief Calculate fuzz: half the distance to the next nearest neighbor for each joystick position. | ||
* | ||
* The goal is to avoid collisions between joystick positions while still maintaining | ||
* the widest tolerance for the analog value. | ||
* | ||
* Example: {10,50,800,1000,300,1600} | ||
* If we just choose the minimum difference for this array the value would | ||
* be 40/2 = 20. | ||
* | ||
* 20 does not leave enough room for the joystick position using 1600 which | ||
* could have a +-100 offset. | ||
* | ||
* Example Fuzz values: {20, 20, 100, 100, 125, 300} now the fuzz for the 1600 | ||
* position is 300 instead of 20 | ||
*/ | ||
void ExpressLRSFiveWay::calcFuzzValues() | ||
{ | ||
for (unsigned int i = 0; i < N_JOY_ADC_VALUES; i++) { | ||
uint16_t closestDist = 0xffff; | ||
uint16_t ival = joyAdcValues[i]; | ||
// Find the closest value to ival | ||
for (unsigned int j = 0; j < N_JOY_ADC_VALUES; j++) { | ||
// Don't compare value with itself | ||
if (j == i) | ||
continue; | ||
uint16_t jval = joyAdcValues[j]; | ||
if (jval < ival && (ival - jval < closestDist)) | ||
closestDist = ival - jval; | ||
if (jval > ival && (jval - ival < closestDist)) | ||
closestDist = jval - ival; | ||
} // for j | ||
|
||
// And the fuzz is half the distance to the closest value | ||
fuzzValues[i] = closestDist / 2; | ||
// DBG("joy%u=%u f=%u, ", i, ival, fuzzValues[i]); | ||
} // for i | ||
} | ||
|
||
int ExpressLRSFiveWay::readKey() | ||
{ | ||
uint16_t value = analogRead(PIN_JOYSTICK); | ||
|
||
constexpr uint8_t IDX_TO_INPUT[N_JOY_ADC_VALUES - 1] = {UP, DOWN, LEFT, RIGHT, OK}; | ||
for (unsigned int i = 0; i < N_JOY_ADC_VALUES - 1; ++i) { | ||
if (value < (joyAdcValues[i] + fuzzValues[i]) && value > (joyAdcValues[i] - fuzzValues[i])) | ||
return IDX_TO_INPUT[i]; | ||
} | ||
return NO_PRESS; | ||
} | ||
|
||
ExpressLRSFiveWay::ExpressLRSFiveWay() : concurrency::OSThread(inputSourceName) | ||
{ | ||
// ExpressLRS: init values | ||
isLongPressed = false; | ||
keyInProcess = NO_PRESS; | ||
keyDownStart = 0; | ||
|
||
// Express LRS: calculate the threshold for interpreting ADC values as various buttons | ||
calcFuzzValues(); | ||
|
||
// Meshtastic: register with canned messages | ||
inputBroker->registerSource(this); | ||
} | ||
|
||
// ExpressLRS: interpret reading as key events | ||
void ExpressLRSFiveWay::update(int *keyValue, bool *keyLongPressed) | ||
{ | ||
*keyValue = NO_PRESS; | ||
|
||
int newKey = readKey(); | ||
uint32_t now = millis(); | ||
if (keyInProcess == NO_PRESS) { | ||
// New key down | ||
if (newKey != NO_PRESS) { | ||
keyDownStart = now; | ||
// DBGLN("down=%u", newKey); | ||
} | ||
} else { | ||
// if key released | ||
if (newKey == NO_PRESS) { | ||
// DBGLN("up=%u", keyInProcess); | ||
if (!isLongPressed) { | ||
if ((now - keyDownStart) > KEY_DEBOUNCE_MS) { | ||
*keyValue = keyInProcess; | ||
*keyLongPressed = false; | ||
} | ||
} | ||
isLongPressed = false; | ||
} | ||
// else if the key has changed while down, reset state for next go-around | ||
else if (newKey != keyInProcess) { | ||
newKey = NO_PRESS; | ||
} | ||
// else still pressing, waiting for long if not already signaled | ||
else if (!isLongPressed) { | ||
if ((now - keyDownStart) > KEY_LONG_PRESS_MS) { | ||
*keyValue = keyInProcess; | ||
*keyLongPressed = true; | ||
isLongPressed = true; | ||
} | ||
} | ||
} // if keyInProcess != NO_PRESS | ||
|
||
keyInProcess = newKey; | ||
} | ||
|
||
// Meshtastic: runs at regular intervals | ||
int32_t ExpressLRSFiveWay::runOnce() | ||
{ | ||
uint32_t now = millis(); | ||
|
||
// Dismiss any alert frames after 2 seconds | ||
// Feedback for GPS toggle / adhoc ping | ||
if (alerting && now > alertingSinceMs + 2000) { | ||
alerting = false; | ||
screen->endAlert(); | ||
} | ||
|
||
// Get key events from ExpressLRS code | ||
int keyValue; | ||
bool longPressed; | ||
update(&keyValue, &longPressed); | ||
|
||
// Do something about this key press | ||
determineAction((KeyType)keyValue, longPressed ? LONG : SHORT); | ||
|
||
// If there has been recent key activity, poll the joystick slightly more frequently | ||
if (now < keyDownStart + (20 * 1000UL)) // Within last 20 seconds | ||
return 100; | ||
|
||
// Otherwise, poll slightly less often | ||
// Too many missed pressed if much slower than 250ms | ||
return 250; | ||
} | ||
|
||
// Determine what action to take when a button press is detected | ||
// Written verbose for easier remapping by user | ||
void ExpressLRSFiveWay::determineAction(KeyType key, PressLength length) | ||
{ | ||
switch (key) { | ||
case LEFT: | ||
if (inCannedMessageMenu()) // If in canned message menu | ||
sendKey(CANCEL); // exit the menu (press imaginary cancel key) | ||
else | ||
sendKey(LEFT); | ||
break; | ||
|
||
case RIGHT: | ||
if (inCannedMessageMenu()) // If in canned message menu: | ||
sendKey(CANCEL); // exit the menu (press imaginary cancel key) | ||
else | ||
sendKey(RIGHT); | ||
break; | ||
|
||
case UP: | ||
if (length == LONG) | ||
toggleGPS(); | ||
else | ||
sendKey(UP); | ||
break; | ||
|
||
case DOWN: | ||
if (length == LONG) | ||
sendAdhocPing(); | ||
else | ||
sendKey(DOWN); | ||
break; | ||
|
||
case OK: | ||
if (length == LONG) | ||
shutdown(); | ||
else | ||
click(); // Use instead of sendKey(OK). Works better when canned message module disabled | ||
break; | ||
|
||
default: | ||
break; | ||
} | ||
} | ||
|
||
// Feed input to the canned messages module | ||
void ExpressLRSFiveWay::sendKey(KeyType key) | ||
{ | ||
InputEvent e; | ||
e.source = inputSourceName; | ||
e.inputEvent = key; | ||
notifyObservers(&e); | ||
} | ||
|
||
// Enable or Disable a connected GPS | ||
// Contained as one method for easier remapping of buttons by user | ||
void ExpressLRSFiveWay::toggleGPS() | ||
{ | ||
#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS | ||
if (!config.device.disable_triple_click && (gps != nullptr)) { | ||
gps->toggleGpsMode(); | ||
screen->startAlert("GPS Toggled"); | ||
alerting = true; | ||
alertingSinceMs = millis(); | ||
} | ||
#endif | ||
} | ||
|
||
// Send either node-info or position, on demand | ||
// Contained as one method for easier remapping of buttons by user | ||
void ExpressLRSFiveWay::sendAdhocPing() | ||
{ | ||
service->refreshLocalMeshNode(); | ||
bool sentPosition = service->trySendPosition(NODENUM_BROADCAST, true); | ||
|
||
// Show custom alert frame, with multi-line centering | ||
screen->startAlert([sentPosition](OLEDDisplay *display, OLEDDisplayUiState *state, int16_t x, int16_t y) -> void { | ||
uint16_t x_offset = display->width() / 2; | ||
uint16_t y_offset = 26; // Same constant as the default startAlert frame | ||
display->setTextAlignment(TEXT_ALIGN_CENTER); | ||
display->setFont(FONT_MEDIUM); | ||
display->drawString(x_offset + x, y_offset + y, "Sent ad-hoc"); | ||
display->drawString(x_offset + x, y_offset + FONT_HEIGHT_MEDIUM + y, sentPosition ? "position" : "nodeinfo"); | ||
}); | ||
|
||
alerting = true; | ||
alertingSinceMs = millis(); | ||
} | ||
|
||
// Shutdown the node (enter deep-sleep) | ||
// Contained as one method for easier remapping of buttons by user | ||
void ExpressLRSFiveWay::shutdown() | ||
{ | ||
LOG_INFO("Shutdown from long press\n"); | ||
powerFSM.trigger(EVENT_PRESS); | ||
screen->startAlert("Shutting down..."); | ||
// Don't set alerting = true. We don't want to auto-dismiss this alert. | ||
|
||
playShutdownMelody(); // In case user adds a buzzer | ||
|
||
shutdownAtMsec = millis() + 3000; | ||
} | ||
|
||
// Emulate user button, or canned message SELECT | ||
// This is necessary as canned message module doesn't translate SELECT to user button presses if the module is disabled | ||
// Contained as one method for easier remapping of buttons by user | ||
void ExpressLRSFiveWay::click() | ||
{ | ||
if (!moduleConfig.canned_message.enabled) | ||
powerFSM.trigger(EVENT_PRESS); | ||
else | ||
sendKey(OK); | ||
} | ||
|
||
ExpressLRSFiveWay *expressLRSFiveWayInput = nullptr; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
/* | ||
Input source for Radio Master Bandit Nano, and similar hardware. | ||
Devices have a 5-button "resistor ladder" style joystick, read by ADC. | ||
These devices do not use the ADC to monitor input voltage. | ||
Much of this code taken directly from ExpressLRS FiveWayButton class: | ||
https://github.com/ExpressLRS/ExpressLRS/tree/d9f56f8bd6f9f7144d5f01caaca766383e1e0950/src/lib/SCREEN/FiveWayButton | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include "configuration.h" | ||
|
||
#ifdef INPUTBROKER_EXPRESSLRSFIVEWAY_TYPE | ||
|
||
#include <esp_adc_cal.h> | ||
#include <soc/adc_channel.h> | ||
|
||
#include "InputBroker.h" | ||
#include "MeshService.h" // For adhoc ping action | ||
#include "buzz.h" | ||
#include "concurrency/OSThread.h" | ||
#include "graphics/Screen.h" // Feedback for adhoc ping / toggle GPS | ||
#include "main.h" | ||
#include "modules/CannedMessageModule.h" | ||
|
||
#if HAS_GPS && !MESHTASTIC_EXCLUDE_GPS | ||
#include "GPS.h" // For toggle GPS action | ||
#endif | ||
|
||
class ExpressLRSFiveWay : public Observable<const InputEvent *>, public concurrency::OSThread | ||
{ | ||
private: | ||
// Number of values in JOY_ADC_VALUES, if defined | ||
// These must be ADC readings for {UP, DOWN, LEFT, RIGHT, ENTER, IDLE} | ||
static constexpr size_t N_JOY_ADC_VALUES = 6; | ||
static constexpr uint32_t KEY_DEBOUNCE_MS = 25; | ||
static constexpr uint32_t KEY_LONG_PRESS_MS = 3000; // How many milliseconds to hold key for a long press | ||
|
||
// This merged an enum used by the ExpressLRS code, with meshtastic canned message values | ||
// Key names are kept simple, to allow user customizaton | ||
typedef enum { | ||
UP = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_UP, | ||
DOWN = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_DOWN, | ||
LEFT = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_LEFT, | ||
RIGHT = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_RIGHT, | ||
OK = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_SELECT, | ||
CANCEL = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_CANCEL, | ||
NO_PRESS = meshtastic_ModuleConfig_CannedMessageConfig_InputEventChar_NONE | ||
} KeyType; | ||
|
||
typedef enum { SHORT, LONG } PressLength; | ||
|
||
// From ExpressLRS | ||
int keyInProcess; | ||
uint32_t keyDownStart; | ||
bool isLongPressed; | ||
const uint16_t joyAdcValues[N_JOY_ADC_VALUES] = {JOYSTICK_ADC_VALS}; | ||
uint16_t fuzzValues[N_JOY_ADC_VALUES]; | ||
void calcFuzzValues(); | ||
int readKey(); | ||
void update(int *keyValue, bool *keyLongPressed); | ||
|
||
// Meshtastic code | ||
void determineAction(KeyType key, PressLength length); | ||
void sendKey(KeyType key); | ||
inline bool inCannedMessageMenu() { return cannedMessageModule->shouldDraw(); } | ||
int32_t runOnce() override; | ||
|
||
// Simplified Meshtastic actions, for easier remapping by user | ||
void toggleGPS(); | ||
void sendAdhocPing(); | ||
void shutdown(); | ||
void click(); | ||
|
||
bool alerting = false; // Is the screen showing an alert frame? Feedback for GPS toggle / adhoc ping actions | ||
uint32_t alertingSinceMs = 0; // When did screen begin showing an alert frame? Used to auto-dismiss | ||
|
||
public: | ||
ExpressLRSFiveWay(); | ||
}; | ||
|
||
extern ExpressLRSFiveWay *expressLRSFiveWayInput; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.