mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
Add Radiomaster Bandit/Bandit Nano support
Added support for 5-Way analog joystick. Added Custom Sh1115 OLED driver. Added NeoPixels support for Radiomaster Bandit. Power output 20-30 dbm (100mW-1000mW). Changed so Analog joystick can be used in UI. Changed so NeoPixels is used for new Message. (Color can be defined). Radiomaster Bandit Micro uses the same code as Nano.
This commit is contained in:
parent
e33d93dc7f
commit
6c0da535b8
17 changed files with 1951 additions and 2 deletions
106
src/helpers/ui/AnalogJoystick.cpp
Normal file
106
src/helpers/ui/AnalogJoystick.cpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
#include "AnalogJoystick.h"
|
||||
|
||||
AnalogJoystick::AnalogJoystick(int8_t pin, JoyADCMapping *mappings, uint8_t num_mappings,
|
||||
uint8_t select_key_code, unsigned long long_press_ms, int tolerance,
|
||||
unsigned long debounce_ms) {
|
||||
_pin = pin;
|
||||
_mappings = mappings;
|
||||
_num_mappings = num_mappings;
|
||||
_select_key = select_key_code;
|
||||
_long_press_ms = long_press_ms;
|
||||
_tolerance = tolerance;
|
||||
_debounce_ms = debounce_ms;
|
||||
prev = 0;
|
||||
_last_change_time = 0;
|
||||
_select_press_start = 0;
|
||||
_long_press_triggered = false;
|
||||
}
|
||||
|
||||
void AnalogJoystick::begin() {
|
||||
if (_pin >= 0) {
|
||||
pinMode(_pin, INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AnalogJoystick::findClosestKey(int adc_value) const {
|
||||
int closest_index = -1;
|
||||
int min_diff = 32767;
|
||||
|
||||
for (uint8_t i = 0; i < _num_mappings; i++) {
|
||||
int diff = abs(adc_value - _mappings[i].adc_value);
|
||||
if (diff < min_diff) {
|
||||
min_diff = diff;
|
||||
closest_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (closest_index >= 0 && min_diff < _tolerance) {
|
||||
return _mappings[closest_index].key_code;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t AnalogJoystick::check() {
|
||||
if (_pin < 0) return 0;
|
||||
|
||||
int adc_value = analogRead(_pin);
|
||||
uint8_t key = findClosestKey(adc_value);
|
||||
|
||||
// Handle SELECT button with long press support
|
||||
if (key == _select_key) {
|
||||
if (_select_press_start == 0) {
|
||||
// SELECT just pressed - start tracking
|
||||
_select_press_start = millis();
|
||||
_long_press_triggered = false;
|
||||
prev = key;
|
||||
} else if (!_long_press_triggered && (millis() - _select_press_start) >= _long_press_ms) {
|
||||
// Long press threshold reached
|
||||
_long_press_triggered = true;
|
||||
return 0xFF; // Special code for long press (only sent once)
|
||||
}
|
||||
// Still holding, waiting for either release or long press
|
||||
return 0;
|
||||
|
||||
} else if (prev == _select_key && _select_press_start > 0) {
|
||||
// SELECT was just released
|
||||
bool was_long_press = _long_press_triggered;
|
||||
_select_press_start = 0;
|
||||
_long_press_triggered = false;
|
||||
prev = key; // Update to new state (likely 0/idle)
|
||||
|
||||
if (!was_long_press) {
|
||||
// Released before long press - this is a click
|
||||
_last_change_time = millis();
|
||||
return _select_key;
|
||||
}
|
||||
// Was long press, already handled, don't send click
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
// Not SELECT button - handle other directions with debouncing
|
||||
if (key != prev) {
|
||||
unsigned long now = millis();
|
||||
if ((now - _last_change_time) > _debounce_ms) {
|
||||
prev = key;
|
||||
_last_change_time = now;
|
||||
return key;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool AnalogJoystick::isLongPress() {
|
||||
return _long_press_triggered;
|
||||
}
|
||||
|
||||
bool AnalogJoystick::isPressed() const {
|
||||
if (_pin < 0) return false;
|
||||
|
||||
int adc_value = analogRead(_pin);
|
||||
uint8_t key = findClosestKey(adc_value);
|
||||
|
||||
// Return true if any key is pressed (not idle/released)
|
||||
return key != 0;
|
||||
}
|
||||
37
src/helpers/ui/AnalogJoystick.h
Normal file
37
src/helpers/ui/AnalogJoystick.h
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class AnalogJoystick {
|
||||
public:
|
||||
struct JoyADCMapping {
|
||||
int adc_value;
|
||||
uint8_t key_code;
|
||||
};
|
||||
|
||||
private:
|
||||
int8_t _pin;
|
||||
uint8_t prev;
|
||||
int _tolerance;
|
||||
unsigned long _debounce_ms;
|
||||
unsigned long _last_change_time; // Long press tracking
|
||||
uint8_t _select_key;
|
||||
unsigned long _select_press_start;
|
||||
bool _long_press_triggered;
|
||||
unsigned long _long_press_ms;
|
||||
|
||||
JoyADCMapping *_mappings;
|
||||
uint8_t _num_mappings;
|
||||
|
||||
uint8_t findClosestKey(int adc_value) const;
|
||||
|
||||
public:
|
||||
AnalogJoystick(int8_t pin, JoyADCMapping *mappings, uint8_t num_mappings, uint8_t select_key_code,
|
||||
unsigned long long_press_ms = 1000, int tolerance = 300, unsigned long debounce_ms = 50);
|
||||
void begin();
|
||||
uint8_t check();
|
||||
bool isLongPress();
|
||||
bool isPressed() const;
|
||||
uint8_t getPin() const { return _pin; }
|
||||
uint8_t getCurrentKey() const { return prev; }
|
||||
};
|
||||
92
src/helpers/ui/SH1115Display.cpp
Normal file
92
src/helpers/ui/SH1115Display.cpp
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
#include "SH1115Display.h"
|
||||
#include <Adafruit_GrayOLED.h>
|
||||
//#include "Adafruit_SH110X.h"
|
||||
#include <Adafruit_SH1115.h>
|
||||
|
||||
bool SH1115Display::i2c_probe(TwoWire &wire, uint8_t addr)
|
||||
{
|
||||
wire.beginTransmission(addr);
|
||||
uint8_t error = wire.endTransmission();
|
||||
return (error == 0);
|
||||
}
|
||||
|
||||
bool SH1115Display::begin()
|
||||
{
|
||||
return display.begin(DISPLAY_ADDRESS, true) && i2c_probe(Wire, DISPLAY_ADDRESS);
|
||||
}
|
||||
|
||||
void SH1115Display::turnOn()
|
||||
{
|
||||
display.oled_command(SH110X_DISPLAYON);
|
||||
_isOn = true;
|
||||
}
|
||||
|
||||
void SH1115Display::turnOff()
|
||||
{
|
||||
display.oled_command(SH110X_DISPLAYOFF);
|
||||
_isOn = false;
|
||||
}
|
||||
|
||||
void SH1115Display::clear()
|
||||
{
|
||||
display.clearDisplay();
|
||||
display.display();
|
||||
}
|
||||
|
||||
void SH1115Display::startFrame(Color bkg)
|
||||
{
|
||||
display.clearDisplay(); // TODO: apply 'bkg'
|
||||
_color = SH110X_WHITE;
|
||||
display.setTextColor(_color);
|
||||
display.setTextSize(1);
|
||||
display.cp437(true); // Use full 256 char 'Code Page 437' font
|
||||
}
|
||||
|
||||
void SH1115Display::setTextSize(int sz)
|
||||
{
|
||||
display.setTextSize(sz);
|
||||
}
|
||||
|
||||
void SH1115Display::setColor(Color c)
|
||||
{
|
||||
_color = (c != 0) ? SH110X_WHITE : SH110X_BLACK;
|
||||
display.setTextColor(_color);
|
||||
}
|
||||
|
||||
void SH1115Display::setCursor(int x, int y)
|
||||
{
|
||||
display.setCursor(x, y);
|
||||
}
|
||||
|
||||
void SH1115Display::print(const char *str)
|
||||
{
|
||||
display.print(str);
|
||||
}
|
||||
|
||||
void SH1115Display::fillRect(int x, int y, int w, int h)
|
||||
{
|
||||
display.fillRect(x, y, w, h, _color);
|
||||
}
|
||||
|
||||
void SH1115Display::drawRect(int x, int y, int w, int h)
|
||||
{
|
||||
display.drawRect(x, y, w, h, _color);
|
||||
}
|
||||
|
||||
void SH1115Display::drawXbm(int x, int y, const uint8_t *bits, int w, int h)
|
||||
{
|
||||
display.drawBitmap(x, y, bits, w, h, SH110X_WHITE);
|
||||
}
|
||||
|
||||
uint16_t SH1115Display::getTextWidth(const char *str)
|
||||
{
|
||||
int16_t x1, y1;
|
||||
uint16_t w, h;
|
||||
display.getTextBounds(str, 0, 0, &x1, &y1, &w, &h);
|
||||
return w;
|
||||
}
|
||||
|
||||
void SH1115Display::endFrame()
|
||||
{
|
||||
display.display();
|
||||
}
|
||||
44
src/helpers/ui/SH1115Display.h
Normal file
44
src/helpers/ui/SH1115Display.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#pragma once
|
||||
|
||||
#include "DisplayDriver.h"
|
||||
|
||||
#include <Adafruit_GFX.h>
|
||||
#include <Wire.h>
|
||||
#define SH110X_NO_SPLASH
|
||||
// #include <Adafruit_SH110X.h>
|
||||
#include <Adafruit_SH1115.h>
|
||||
|
||||
#ifndef PIN_OLED_RESET
|
||||
#define PIN_OLED_RESET -1
|
||||
#endif
|
||||
|
||||
#ifndef DISPLAY_ADDRESS
|
||||
#define DISPLAY_ADDRESS 0x3C
|
||||
#endif
|
||||
|
||||
class SH1115Display : public DisplayDriver {
|
||||
Adafruit_SH1115 display;
|
||||
bool _isOn;
|
||||
uint8_t _color;
|
||||
|
||||
bool i2c_probe(TwoWire &wire, uint8_t addr);
|
||||
|
||||
public:
|
||||
SH1115Display() : DisplayDriver(128, 64), display(128, 64, &Wire, PIN_OLED_RESET) { _isOn = false; }
|
||||
bool begin();
|
||||
|
||||
bool isOn() override { return _isOn; }
|
||||
void turnOn() override;
|
||||
void turnOff() override;
|
||||
void clear() override;
|
||||
void startFrame(Color bkg = DARK) override;
|
||||
void setTextSize(int sz) override;
|
||||
void setColor(Color c) override;
|
||||
void setCursor(int x, int y) override;
|
||||
void print(const char *str) override;
|
||||
void fillRect(int x, int y, int w, int h) override;
|
||||
void drawRect(int x, int y, int w, int h) override;
|
||||
void drawXbm(int x, int y, const uint8_t *bits, int w, int h) override;
|
||||
uint16_t getTextWidth(const char *str) override;
|
||||
void endFrame() override;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue