mirror of https://github.com/meshcore-dev/MeshCore
6 changed files with 433 additions and 0 deletions
@ -0,0 +1,125 @@ |
|||
#include "LGFXDisplay.h" |
|||
|
|||
bool LGFXDisplay::begin() { |
|||
turnOn(); |
|||
display->init(); |
|||
display->setRotation(1); |
|||
display->setBrightness(64); |
|||
display->setColorDepth(8); |
|||
display->setTextColor(TFT_WHITE); |
|||
|
|||
buffer.setColorDepth(8); |
|||
buffer.setPsram(true); |
|||
buffer.createSprite(width(), height()); |
|||
|
|||
return true; |
|||
} |
|||
|
|||
void LGFXDisplay::turnOn() { |
|||
// display->wakeup();
|
|||
if (!_isOn) { |
|||
display->wakeup(); |
|||
} |
|||
_isOn = true; |
|||
} |
|||
|
|||
void LGFXDisplay::turnOff() { |
|||
if (_isOn) { |
|||
display->sleep(); |
|||
} |
|||
_isOn = false; |
|||
} |
|||
|
|||
void LGFXDisplay::clear() { |
|||
// display->clearDisplay();
|
|||
buffer.clearDisplay(); |
|||
} |
|||
|
|||
void LGFXDisplay::startFrame(Color bkg) { |
|||
// display->startWrite();
|
|||
// display->getScanLine();
|
|||
buffer.clearDisplay(); |
|||
buffer.setTextColor(TFT_WHITE); |
|||
} |
|||
|
|||
void LGFXDisplay::setTextSize(int sz) { |
|||
buffer.setTextSize(sz); |
|||
} |
|||
|
|||
void LGFXDisplay::setColor(Color c) { |
|||
// _color = (c != 0) ? ILI9342_WHITE : ILI9342_BLACK;
|
|||
switch (c) { |
|||
case DARK: |
|||
_color = TFT_BLACK; |
|||
break; |
|||
case LIGHT: |
|||
_color = TFT_WHITE; |
|||
break; |
|||
case RED: |
|||
_color = TFT_RED; |
|||
break; |
|||
case GREEN: |
|||
_color = TFT_GREEN; |
|||
break; |
|||
case BLUE: |
|||
_color = TFT_BLUE; |
|||
break; |
|||
case YELLOW: |
|||
_color = TFT_YELLOW; |
|||
break; |
|||
case ORANGE: |
|||
_color = TFT_ORANGE; |
|||
break; |
|||
default: |
|||
_color = TFT_WHITE; |
|||
} |
|||
buffer.setTextColor(_color); |
|||
} |
|||
|
|||
void LGFXDisplay::setCursor(int x, int y) { |
|||
buffer.setCursor(x, y); |
|||
} |
|||
|
|||
void LGFXDisplay::print(const char* str) { |
|||
buffer.println(str); |
|||
// Serial.println(str);
|
|||
} |
|||
|
|||
void LGFXDisplay::fillRect(int x, int y, int w, int h) { |
|||
buffer.fillRect(x, y, w, h, _color); |
|||
} |
|||
|
|||
void LGFXDisplay::drawRect(int x, int y, int w, int h) { |
|||
buffer.drawRect(x, y, w, h, _color); |
|||
} |
|||
|
|||
void LGFXDisplay::drawXbm(int x, int y, const uint8_t* bits, int w, int h) { |
|||
buffer.drawBitmap(x, y, bits, w, h, _color); |
|||
} |
|||
|
|||
uint16_t LGFXDisplay::getTextWidth(const char* str) { |
|||
return buffer.textWidth(str); |
|||
} |
|||
|
|||
void LGFXDisplay::endFrame() { |
|||
display->startWrite(); |
|||
if (UI_ZOOM != 1) { |
|||
buffer.pushRotateZoom(display, display->width()/2, display->height()/2 , 0, UI_ZOOM, UI_ZOOM); |
|||
} else { |
|||
buffer.pushSprite(display, 0, 0); |
|||
} |
|||
display->endWrite(); |
|||
} |
|||
|
|||
bool LGFXDisplay::getTouch(int *x, int *y) { |
|||
lgfx::v1::touch_point_t point; |
|||
display->getTouch(&point); |
|||
if (UI_ZOOM != 1) { |
|||
*x = point.x / UI_ZOOM; |
|||
*y = point.y / UI_ZOOM; |
|||
} else { |
|||
*x = point.x; |
|||
*y = point.y; |
|||
} |
|||
return (*x >= 0) && (*y >= 0); |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
|
|||
/*
|
|||
* Base class for LovyanGFX supported display (works on ESP32 mainly) |
|||
* You can extend this class to support your display, providing your own LGFX |
|||
*/ |
|||
|
|||
#pragma once |
|||
|
|||
#include <helpers/ui/DisplayDriver.h> |
|||
|
|||
#define LGFX_USE_V1 |
|||
#include <LovyanGFX.hpp> |
|||
|
|||
#ifndef UI_ZOOM |
|||
#define UI_ZOOM 1 |
|||
#endif |
|||
|
|||
class LGFXDisplay : public DisplayDriver { |
|||
protected: |
|||
LGFX_Device* display; |
|||
LGFX_Sprite buffer; |
|||
|
|||
bool _isOn; |
|||
int _color = TFT_WHITE; |
|||
|
|||
public: |
|||
LGFXDisplay(int w, int h):DisplayDriver(w/UI_ZOOM, h/UI_ZOOM) {_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; |
|||
virtual bool getTouch(int *x, int *y); |
|||
}; |
|||
@ -0,0 +1,129 @@ |
|||
#pragma once |
|||
|
|||
#include <helpers/ui/LGFXDisplay.h> |
|||
|
|||
#define LGFX_USE_V1 |
|||
#include <LovyanGFX.hpp> |
|||
|
|||
#include <lgfx/v1/platforms/esp32s3/Panel_RGB.hpp> |
|||
#include <lgfx/v1/platforms/esp32s3/Bus_RGB.hpp> |
|||
|
|||
class LGFX : public lgfx::LGFX_Device |
|||
{ |
|||
lgfx::Panel_ST7701 _panel_instance; |
|||
lgfx::Bus_RGB _bus_instance; |
|||
lgfx::Light_PWM _light_instance; |
|||
lgfx::Touch_FT5x06 _touch_instance; |
|||
|
|||
public: |
|||
const uint16_t screenWidth = 480; |
|||
const uint16_t screenHeight = 480; |
|||
|
|||
bool hasButton(void) { return true; } |
|||
|
|||
LGFX(void) |
|||
{ |
|||
{ |
|||
auto cfg = _panel_instance.config(); |
|||
cfg.memory_width = 480; |
|||
cfg.memory_height = 480; |
|||
cfg.panel_width = screenWidth; |
|||
cfg.panel_height = screenHeight; |
|||
cfg.offset_x = 0; |
|||
cfg.offset_y = 0; |
|||
cfg.offset_rotation = 1; |
|||
_panel_instance.config(cfg); |
|||
} |
|||
|
|||
{ |
|||
auto cfg = _panel_instance.config_detail(); |
|||
cfg.pin_cs = 4 | IO_EXPANDER; |
|||
cfg.pin_sclk = 41; |
|||
cfg.pin_mosi = 48; |
|||
cfg.use_psram = 1; |
|||
_panel_instance.config_detail(cfg); |
|||
} |
|||
|
|||
{ |
|||
auto cfg = _bus_instance.config(); |
|||
cfg.panel = &_panel_instance; |
|||
|
|||
cfg.freq_write = 8000000; |
|||
cfg.pin_henable = 18; |
|||
|
|||
cfg.pin_pclk = 21; |
|||
cfg.pclk_active_neg = 0; |
|||
cfg.pclk_idle_high = 0; |
|||
cfg.de_idle_high = 1; |
|||
|
|||
cfg.pin_hsync = 16; |
|||
cfg.hsync_polarity = 0; |
|||
cfg.hsync_front_porch = 10; |
|||
cfg.hsync_pulse_width = 8; |
|||
cfg.hsync_back_porch = 50; |
|||
|
|||
cfg.pin_vsync = 17; |
|||
cfg.vsync_polarity = 0; |
|||
cfg.vsync_front_porch = 10; |
|||
cfg.vsync_pulse_width = 8; |
|||
cfg.vsync_back_porch = 20; |
|||
|
|||
cfg.pin_d0 = 15; |
|||
cfg.pin_d1 = 14; |
|||
cfg.pin_d2 = 13; |
|||
cfg.pin_d3 = 12; |
|||
cfg.pin_d4 = 11; |
|||
cfg.pin_d5 = 10; |
|||
cfg.pin_d6 = 9; |
|||
cfg.pin_d7 = 8; |
|||
cfg.pin_d8 = 7; |
|||
cfg.pin_d9 = 6; |
|||
cfg.pin_d10 = 5; |
|||
cfg.pin_d11 = 4; |
|||
cfg.pin_d12 = 3; |
|||
cfg.pin_d13 = 2; |
|||
cfg.pin_d14 = 1; |
|||
cfg.pin_d15 = 0; |
|||
|
|||
_bus_instance.config(cfg); |
|||
} |
|||
_panel_instance.setBus(&_bus_instance); |
|||
|
|||
{ |
|||
auto cfg = _light_instance.config(); |
|||
cfg.pin_bl = 45; |
|||
_light_instance.config(cfg); |
|||
} |
|||
_panel_instance.light(&_light_instance); |
|||
|
|||
{ |
|||
auto cfg = _touch_instance.config(); |
|||
cfg.pin_cs = GPIO_NUM_NC; |
|||
cfg.x_min = 0; |
|||
cfg.x_max = 479; |
|||
cfg.y_min = 0; |
|||
cfg.y_max = 479; |
|||
cfg.pin_int = GPIO_NUM_NC; |
|||
cfg.pin_rst = GPIO_NUM_NC; |
|||
cfg.bus_shared = true; |
|||
cfg.offset_rotation = 0; |
|||
|
|||
cfg.i2c_port = 0; |
|||
cfg.i2c_addr = 0x48; |
|||
cfg.pin_sda = 39; |
|||
cfg.pin_scl = 40; |
|||
cfg.freq = 400000; |
|||
_touch_instance.config(cfg); |
|||
_panel_instance.setTouch(&_touch_instance); |
|||
} |
|||
|
|||
setPanel(&_panel_instance); |
|||
} |
|||
}; |
|||
|
|||
class SCIndicatorDisplay : public LGFXDisplay { |
|||
LGFX disp; |
|||
public: |
|||
SCIndicatorDisplay() : LGFXDisplay(480, 480) |
|||
{ display=&disp; } |
|||
}; |
|||
@ -0,0 +1,50 @@ |
|||
[SenseCapIndicator-ESPNow] |
|||
extends = esp32_base |
|||
board = esp32-s3-devkitc-1 |
|||
board_build.arduino.memory_type = qio_opi |
|||
board_build.flash_mode = qio |
|||
board_build.psram_type = opi |
|||
board_upload.flash_size = 8MB |
|||
board_upload.maximum_size = 8388608 |
|||
board_build.partitions = default.csv |
|||
build_flags = |
|||
${esp32_base.build_flags} |
|||
-D PIN_BOARD_SDA=39 |
|||
-D PIN_BOARD_SCL=40 |
|||
-D DISPLAY_CLASS=SCIndicatorDisplay |
|||
-D DISPLAY_LINES=21 |
|||
-D LINE_LENGTH=53 |
|||
-D DISABLE_WIFI_OTA=1 |
|||
-D IO_EXPANDER=0x40 |
|||
-D IO_EXPANDER_IRQ=42 |
|||
-D UI_ZOOM=3.5 |
|||
-D UI_RECENT_LIST_SIZE=9 |
|||
-D UI_SENSORS_PAGE=1 |
|||
-D PIN_USER_BTN=38 |
|||
-D HAS_TOUCH |
|||
-I variants/sensecap_indicator-espnow |
|||
build_src_filter = ${esp32_base.build_src_filter} |
|||
+<../variants/sensecap_indicator-espnow/*.cpp> |
|||
+<helpers/esp32/ESPNOWRadio.cpp> |
|||
+<helpers/ui/LGFXDisplay.cpp> |
|||
+<helpers/sensors/*> |
|||
lib_deps=${esp32_base.lib_deps} |
|||
adafruit/Adafruit BusIO @ ^1.17.2 |
|||
lovyan03/LovyanGFX @ ^1.2.7 |
|||
|
|||
[env:SenseCapIndicator-ESPNow_comp_radio_usb] |
|||
extends =SenseCapIndicator-ESPNow |
|||
build_flags = |
|||
${SenseCapIndicator-ESPNow.build_flags} |
|||
-I examples/companion_radio/ui-new |
|||
-D MAX_CONTACTS=300 |
|||
-D MAX_GROUP_CHANNELS=8 |
|||
; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 |
|||
; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 |
|||
; NOTE: DO NOT ENABLE --> -D ESPNOW_DEBUG_LOGGING=1 |
|||
build_src_filter = ${SenseCapIndicator-ESPNow.build_src_filter} |
|||
+<../examples/companion_radio/ui-new/*.cpp> |
|||
+<../examples/companion_radio/*.cpp> |
|||
lib_deps = |
|||
${SenseCapIndicator-ESPNow.lib_deps} |
|||
densaugeo/base64 @ ~1.4.0 |
|||
@ -0,0 +1,56 @@ |
|||
#include <Arduino.h> |
|||
#include "target.h" |
|||
#include <helpers/ArduinoHelpers.h> |
|||
|
|||
ESP32Board board; |
|||
|
|||
ESPNOWRadio radio_driver; |
|||
|
|||
ESP32RTCClock rtc_clock; |
|||
#if defined(ENV_INCLUDE_GPS) |
|||
MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, (mesh::RTCClock*)&rtc_clock); |
|||
EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); |
|||
#else |
|||
EnvironmentSensorManager sensors = EnvironmentSensorManager(); |
|||
#endif |
|||
|
|||
#ifdef DISPLAY_CLASS |
|||
DISPLAY_CLASS display; |
|||
#ifdef PIN_USER_BTN |
|||
MomentaryButton user_btn(PIN_USER_BTN, 1000, true, true); |
|||
#endif |
|||
#endif |
|||
|
|||
bool radio_init() { |
|||
rtc_clock.begin(); |
|||
|
|||
radio_driver.init(); |
|||
|
|||
return true; // success
|
|||
} |
|||
|
|||
uint32_t radio_get_rng_seed() { |
|||
return millis() + radio_driver.intID(); // TODO: where to get some entropy?
|
|||
} |
|||
|
|||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { |
|||
// no-op
|
|||
} |
|||
|
|||
void radio_set_tx_power(uint8_t dbm) { |
|||
radio_driver.setTxPower(dbm); |
|||
} |
|||
|
|||
// NOTE: as we are using the WiFi radio, the ESP_IDF will have enabled hardware RNG:
|
|||
// https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/random.html
|
|||
class ESP_RNG : public mesh::RNG { |
|||
public: |
|||
void random(uint8_t* dest, size_t sz) override { |
|||
esp_fill_random(dest, sz); |
|||
} |
|||
}; |
|||
|
|||
mesh::LocalIdentity radio_new_identity() { |
|||
ESP_RNG rng; |
|||
return mesh::LocalIdentity(&rng); // create new random identity
|
|||
} |
|||
@ -0,0 +1,29 @@ |
|||
#pragma once |
|||
|
|||
#include <helpers/ESP32Board.h> |
|||
#include <helpers/esp32/ESPNOWRadio.h> |
|||
#include <helpers/SensorManager.h> |
|||
#include <helpers/sensors/EnvironmentSensorManager.h> |
|||
#ifdef ENV_INCLUDE_GPS |
|||
#include <helpers/sensors/MicroNMEALocationProvider.h> |
|||
#endif |
|||
#ifdef DISPLAY_CLASS |
|||
#include "SCIndicatorDisplay.h" |
|||
#include <helpers/ui/MomentaryButton.h> |
|||
#endif |
|||
|
|||
extern ESP32Board board; |
|||
extern ESPNOWRadio radio_driver; |
|||
extern ESP32RTCClock rtc_clock; |
|||
extern EnvironmentSensorManager sensors; |
|||
|
|||
#ifdef DISPLAY_CLASS |
|||
extern DISPLAY_CLASS display; |
|||
extern MomentaryButton user_btn; |
|||
#endif |
|||
|
|||
bool radio_init(); |
|||
uint32_t radio_get_rng_seed(); |
|||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); |
|||
void radio_set_tx_power(uint8_t dbm); |
|||
mesh::LocalIdentity radio_new_identity(); |
|||
Loading…
Reference in new issue