mirror of
https://github.com/meshcore-dev/MeshCore.git
synced 2026-04-20 22:13:47 +00:00
* UI revamp for companion radios
This commit is contained in:
parent
a310a5c4d5
commit
4b95c981bb
26 changed files with 840 additions and 323 deletions
|
|
@ -83,6 +83,7 @@ void SerialBLEInterface::onConnect(BLEServer* pServer) {
|
|||
|
||||
void SerialBLEInterface::onConnect(BLEServer* pServer, esp_ble_gatts_cb_param_t *param) {
|
||||
BLE_DEBUG_PRINTLN("onConnect(), conn_id=%d, mtu=%d", param->connect.conn_id, pServer->getPeerMTU(param->connect.conn_id));
|
||||
last_conn_id = param->connect.conn_id;
|
||||
}
|
||||
|
||||
void SerialBLEInterface::onMtuChanged(BLEServer* pServer, esp_ble_gatts_cb_param_t* param) {
|
||||
|
|
@ -143,6 +144,7 @@ void SerialBLEInterface::disable() {
|
|||
BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
|
||||
|
||||
pServer->getAdvertising()->stop();
|
||||
pServer->disconnect(last_conn_id);
|
||||
pService->stop();
|
||||
oldDeviceConnected = deviceConnected = false;
|
||||
adv_restart_time = 0;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ class SerialBLEInterface : public BaseSerialInterface, BLESecurityCallbacks, BLE
|
|||
bool deviceConnected;
|
||||
bool oldDeviceConnected;
|
||||
bool _isEnabled;
|
||||
uint16_t last_conn_id;
|
||||
uint32_t _pin_code;
|
||||
unsigned long _last_write;
|
||||
unsigned long adv_restart_time;
|
||||
|
|
@ -56,6 +57,7 @@ public:
|
|||
adv_restart_time = 0;
|
||||
_isEnabled = false;
|
||||
_last_write = 0;
|
||||
last_conn_id = 0;
|
||||
send_queue_len = recv_queue_len = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -115,6 +115,16 @@ void SerialBLEInterface::enable() {
|
|||
void SerialBLEInterface::disable() {
|
||||
_isEnabled = false;
|
||||
BLE_DEBUG_PRINTLN("SerialBLEInterface::disable");
|
||||
|
||||
uint16_t conn_id;
|
||||
if (Bluefruit.getConnectedHandles(&conn_id, 1) > 0) {
|
||||
Bluefruit.disconnect(conn_id);
|
||||
}
|
||||
|
||||
Bluefruit.Advertising.restartOnDisconnect(false);
|
||||
Bluefruit.Advertising.stop();
|
||||
Bluefruit.Advertising.clearData();
|
||||
|
||||
stopAdv();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,5 +60,9 @@ public:
|
|||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
sd_power_system_off();
|
||||
}
|
||||
|
||||
bool startOTAUpdate(const char* id, char reply[]) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -55,4 +55,8 @@ public:
|
|||
void reboot() override {
|
||||
NVIC_SystemReset();
|
||||
}
|
||||
|
||||
void powerOff() override {
|
||||
sd_power_system_off();
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,9 +21,15 @@ public:
|
|||
virtual void setColor(Color c) = 0;
|
||||
virtual void setCursor(int x, int y) = 0;
|
||||
virtual void print(const char* str) = 0;
|
||||
virtual void printWordWrap(const char* str, int max_width) { print(str); } // fallback to basic print() if no override
|
||||
virtual void fillRect(int x, int y, int w, int h) = 0;
|
||||
virtual void drawRect(int x, int y, int w, int h) = 0;
|
||||
virtual void drawXbm(int x, int y, const uint8_t* bits, int w, int h) = 0;
|
||||
virtual uint16_t getTextWidth(const char* str) = 0;
|
||||
virtual void drawTextCentered(int mid_x, int y, const char* str) { // helper method (override to optimise)
|
||||
int w = getTextWidth(str);
|
||||
setCursor(mid_x - w/2, y);
|
||||
print(str);
|
||||
}
|
||||
virtual void endFrame() = 0;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ void GxEPDDisplay::clear() {
|
|||
|
||||
void GxEPDDisplay::startFrame(Color bkg) {
|
||||
display.fillScreen(GxEPD_WHITE);
|
||||
display.setTextColor(_curr_color = GxEPD_BLACK);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::setTextSize(int sz) {
|
||||
|
|
@ -67,7 +68,11 @@ void GxEPDDisplay::setTextSize(int sz) {
|
|||
}
|
||||
|
||||
void GxEPDDisplay::setColor(Color c) {
|
||||
display.setTextColor(GxEPD_BLACK);
|
||||
if (c == DARK) {
|
||||
display.setTextColor(_curr_color = GxEPD_BLACK);
|
||||
} else {
|
||||
display.setTextColor(_curr_color = GxEPD_WHITE);
|
||||
}
|
||||
}
|
||||
|
||||
void GxEPDDisplay::setCursor(int x, int y) {
|
||||
|
|
@ -79,11 +84,11 @@ void GxEPDDisplay::print(const char* str) {
|
|||
}
|
||||
|
||||
void GxEPDDisplay::fillRect(int x, int y, int w, int h) {
|
||||
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, GxEPD_BLACK);
|
||||
display.fillRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::drawRect(int x, int y, int w, int h) {
|
||||
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, GxEPD_BLACK);
|
||||
display.drawRect(x*SCALE_X, y*SCALE_Y, w*SCALE_X, h*SCALE_Y, _curr_color);
|
||||
}
|
||||
|
||||
void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
||||
|
|
@ -116,7 +121,7 @@ void GxEPDDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) {
|
|||
// If the bit is set, draw a block of pixels
|
||||
if (bitSet) {
|
||||
// Draw the block as a filled rectangle
|
||||
display.fillRect(x1, y1, block_w, block_h, GxEPD_BLACK);
|
||||
display.fillRect(x1, y1, block_w, block_h, _curr_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ class GxEPDDisplay : public DisplayDriver {
|
|||
GxEPD2_BW<GxEPD2_150_BN, 200> display;
|
||||
bool _init = false;
|
||||
bool _isOn = false;
|
||||
uint16_t _curr_color;
|
||||
|
||||
public:
|
||||
// there is a margin in y...
|
||||
|
|
|
|||
74
src/helpers/ui/MomentaryButton.cpp
Normal file
74
src/helpers/ui/MomentaryButton.cpp
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
#include "MomentaryButton.h"
|
||||
|
||||
MomentaryButton::MomentaryButton(int8_t pin, int long_press_millis, bool reverse) {
|
||||
_pin = pin;
|
||||
_reverse = reverse;
|
||||
down_at = 0;
|
||||
prev = _reverse ? HIGH : LOW;
|
||||
cancel = 0;
|
||||
_long_millis = long_press_millis;
|
||||
}
|
||||
|
||||
void MomentaryButton::begin(bool pulldownup) {
|
||||
if (_pin >= 0) {
|
||||
pinMode(_pin, pulldownup ? (_reverse ? INPUT_PULLUP : INPUT_PULLDOWN) : INPUT);
|
||||
}
|
||||
}
|
||||
|
||||
bool MomentaryButton::isPressed() const {
|
||||
return isPressed(digitalRead(_pin));
|
||||
}
|
||||
|
||||
void MomentaryButton::cancelClick() {
|
||||
cancel = 1;
|
||||
}
|
||||
|
||||
bool MomentaryButton::isPressed(int level) const {
|
||||
if (_reverse) {
|
||||
return level == LOW;
|
||||
} else {
|
||||
return level != LOW;
|
||||
}
|
||||
}
|
||||
|
||||
int MomentaryButton::check(bool repeat_click) {
|
||||
if (_pin < 0) return BUTTON_EVENT_NONE;
|
||||
|
||||
int event = BUTTON_EVENT_NONE;
|
||||
int btn = digitalRead(_pin);
|
||||
if (btn != prev) {
|
||||
if (isPressed(btn)) {
|
||||
down_at = millis();
|
||||
} else {
|
||||
// button UP
|
||||
if (_long_millis > 0) {
|
||||
if (down_at > 0 && (unsigned long)(millis() - down_at) < _long_millis) { // only a CLICK if still within the long_press millis
|
||||
event = BUTTON_EVENT_CLICK;
|
||||
}
|
||||
} else {
|
||||
event = BUTTON_EVENT_CLICK; // any UP results in CLICK event when NOT using long_press feature
|
||||
}
|
||||
if (event == BUTTON_EVENT_CLICK && cancel) {
|
||||
event = BUTTON_EVENT_NONE;
|
||||
}
|
||||
down_at = 0;
|
||||
}
|
||||
prev = btn;
|
||||
}
|
||||
if (!isPressed(btn) && cancel) { // always clear the pending 'cancel' once button is back in UP state
|
||||
cancel = 0;
|
||||
}
|
||||
|
||||
if (_long_millis > 0 && down_at > 0 && (unsigned long)(millis() - down_at) >= _long_millis) {
|
||||
event = BUTTON_EVENT_LONG_PRESS;
|
||||
down_at = 0;
|
||||
}
|
||||
if (down_at > 0 && repeat_click) {
|
||||
unsigned long diff = (unsigned long)(millis() - down_at);
|
||||
if (diff >= 700) {
|
||||
event = BUTTON_EVENT_CLICK; // wait 700 millis before repeating the click events
|
||||
}
|
||||
}
|
||||
|
||||
return event;
|
||||
}
|
||||
25
src/helpers/ui/MomentaryButton.h
Normal file
25
src/helpers/ui/MomentaryButton.h
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
#define BUTTON_EVENT_NONE 0
|
||||
#define BUTTON_EVENT_CLICK 1
|
||||
#define BUTTON_EVENT_LONG_PRESS 2
|
||||
|
||||
class MomentaryButton {
|
||||
int8_t _pin;
|
||||
int8_t prev, cancel;
|
||||
bool _reverse;
|
||||
int _long_millis;
|
||||
unsigned long down_at;
|
||||
|
||||
bool isPressed(int level) const;
|
||||
|
||||
public:
|
||||
MomentaryButton(int8_t pin, int long_press_mills=0, bool reverse=false);
|
||||
void begin(bool pulldownup=false);
|
||||
int check(bool repeat_click=false); // returns one of BUTTON_EVENT_*
|
||||
void cancelClick(); // suppress next BUTTON_EVENT_CLICK (if already in DOWN state)
|
||||
uint8_t getPin() { return _pin; }
|
||||
bool isPressed() const;
|
||||
};
|
||||
|
|
@ -62,6 +62,9 @@ void ST7789Display::clear() {
|
|||
|
||||
void ST7789Display::startFrame(Color bkg) {
|
||||
display.clear();
|
||||
_color = ST77XX_WHITE;
|
||||
display.setRGB(_color);
|
||||
display.setFont(ArialMT_Plain_16);
|
||||
}
|
||||
|
||||
void ST7789Display::setTextSize(int sz) {
|
||||
|
|
@ -81,7 +84,9 @@ void ST7789Display::setColor(Color c) {
|
|||
switch (c) {
|
||||
case DisplayDriver::DARK :
|
||||
_color = ST77XX_BLACK;
|
||||
display.setColor(OLEDDISPLAY_COLOR::BLACK);
|
||||
break;
|
||||
#if 0
|
||||
case DisplayDriver::LIGHT :
|
||||
_color = ST77XX_WHITE;
|
||||
break;
|
||||
|
|
@ -100,8 +105,10 @@ void ST7789Display::setColor(Color c) {
|
|||
case DisplayDriver::ORANGE :
|
||||
_color = ST77XX_ORANGE;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
_color = ST77XX_WHITE;
|
||||
display.setColor(OLEDDISPLAY_COLOR::WHITE);
|
||||
break;
|
||||
}
|
||||
display.setRGB(_color);
|
||||
|
|
@ -116,6 +123,10 @@ void ST7789Display::print(const char* str) {
|
|||
display.drawString(_x, _y, str);
|
||||
}
|
||||
|
||||
void ST7789Display::printWordWrap(const char* str, int max_width) {
|
||||
display.drawStringMaxWidth(_x, _y, max_width*SCALE_X, str);
|
||||
}
|
||||
|
||||
void ST7789Display::fillRect(int x, int y, int w, int h) {
|
||||
display.fillRect(x*SCALE_X + X_OFFSET, y*SCALE_Y + Y_OFFSET, w*SCALE_X, h*SCALE_Y);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public:
|
|||
void setColor(Color c) override;
|
||||
void setCursor(int x, int y) override;
|
||||
void print(const char* str) override;
|
||||
void printWordWrap(const char* str, int max_width) 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;
|
||||
|
|
|
|||
21
src/helpers/ui/UIScreen.h
Normal file
21
src/helpers/ui/UIScreen.h
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
#pragma once
|
||||
|
||||
#include "DisplayDriver.h"
|
||||
|
||||
#define KEY_LEFT 0xB4
|
||||
#define KEY_UP 0xB5
|
||||
#define KEY_DOWN 0xB6
|
||||
#define KEY_RIGHT 0xB7
|
||||
#define KEY_SELECT 10
|
||||
#define KEY_ENTER 13
|
||||
#define KEY_BACK 27 // Esc
|
||||
|
||||
class UIScreen {
|
||||
protected:
|
||||
UIScreen() { }
|
||||
public:
|
||||
virtual int render(DisplayDriver& display) =0; // return value is number of millis until next render
|
||||
virtual bool handleInput(char c) { return false; }
|
||||
virtual void poll() { }
|
||||
};
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue