Merge develop into main (#316)
- Updated all boards to use `hal::Configuration.createDevices` - Updated all boards to use new directory structure and file naming convention - Refactored `Xpt2046SoftSpi` driver. - Created `Axp2101Power` device in `Drivers/AXP2101` - Removed global static instances from some drivers (instances that kept a reference to the Device*) - Improved `SystemInfoApp` UI: better memory labels, hide external memory bar when there's no PSRAM - Fix for HAL: register touch devices after displays are registered - Fix for Boot splash hanging on WiFi init: unlock file lock after using it
This commit is contained in:
committed by
GitHub
parent
1deaf4c426
commit
1627b9fa85
@@ -21,8 +21,8 @@ public:
|
||||
|
||||
explicit Axp2101(i2c_port_t port) : I2cDevice(port, AXP2101_ADDRESS) {}
|
||||
|
||||
std::string getName() const final { return "AXP2101"; }
|
||||
std::string getDescription() const final { return "Power management with I2C interface."; }
|
||||
std::string getName() const override { return "AXP2101"; }
|
||||
std::string getDescription() const override { return "Power management with I2C interface."; }
|
||||
|
||||
bool setRegisters(uint8_t* bytePairs, size_t bytePairsSize) const;
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "Axp2101Power.h"
|
||||
|
||||
bool Axp2101Power::supportsMetric(MetricType type) const {
|
||||
switch (type) {
|
||||
using enum MetricType;
|
||||
case BatteryVoltage:
|
||||
case IsCharging:
|
||||
case ChargeLevel:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
return false; // Safety guard for when new enum values are introduced
|
||||
}
|
||||
|
||||
bool Axp2101Power::getMetric(MetricType type, MetricData& data) {
|
||||
switch (type) {
|
||||
using enum MetricType;
|
||||
case BatteryVoltage: {
|
||||
float milliVolt;
|
||||
if (axpDevice->getBatteryVoltage(milliVolt)) {
|
||||
data.valueAsUint32 = (uint32_t)milliVolt;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case ChargeLevel: {
|
||||
float vbatMillis;
|
||||
if (axpDevice->getBatteryVoltage(vbatMillis)) {
|
||||
float vbat = vbatMillis / 1000.f;
|
||||
float max_voltage = 4.20f;
|
||||
float min_voltage = 2.69f; // From M5Unified
|
||||
if (vbat > 2.69f) {
|
||||
float charge_factor = (vbat - min_voltage) / (max_voltage - min_voltage);
|
||||
data.valueAsUint8 = (uint8_t)(charge_factor * 100.f);
|
||||
} else {
|
||||
data.valueAsUint8 = 0;
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
case IsCharging: {
|
||||
Axp2101::ChargeStatus status;
|
||||
if (axpDevice->getChargeStatus(status)) {
|
||||
data.valueAsBool = (status == Axp2101::CHARGE_STATUS_CHARGING);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Axp2101Power::isAllowedToCharge() const {
|
||||
bool enabled;
|
||||
if (axpDevice->isChargingEnabled(enabled)) {
|
||||
return enabled;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void Axp2101Power::setAllowedToCharge(bool canCharge) {
|
||||
axpDevice->setChargingEnabled(canCharge);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "Tactility/hal/power/PowerDevice.h"
|
||||
#include <Axp2101.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
using tt::hal::power::PowerDevice;
|
||||
|
||||
class Axp2101Power final : public PowerDevice {
|
||||
|
||||
std::shared_ptr<Axp2101> axpDevice;
|
||||
|
||||
public:
|
||||
|
||||
explicit Axp2101Power(std::shared_ptr<Axp2101> axp) : axpDevice(std::move(axp)) {}
|
||||
~Axp2101Power() override = default;
|
||||
|
||||
std::string getName() const override { return "AXP2101 Power"; }
|
||||
std::string getDescription() const override { return "Power management via AXP2101 over I2C"; }
|
||||
|
||||
bool supportsMetric(MetricType type) const override;
|
||||
bool getMetric(MetricType type, MetricData& data) override;
|
||||
|
||||
bool supportsChargeControl() const override { return true; }
|
||||
bool isAllowedToCharge() const override;
|
||||
void setAllowedToCharge(bool canCharge) override;
|
||||
};
|
||||
@@ -102,13 +102,3 @@ bool Xpt2046Power::readBatteryVoltageSampled(uint32_t& output) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static std::shared_ptr<PowerDevice> power;
|
||||
|
||||
std::shared_ptr<PowerDevice> getOrCreatePower() {
|
||||
if (power == nullptr) {
|
||||
power = std::make_shared<Xpt2046Power>();
|
||||
}
|
||||
return power;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,14 +18,11 @@ class Xpt2046Power : public PowerDevice {
|
||||
|
||||
public:
|
||||
|
||||
~Xpt2046Power() = default;
|
||||
~Xpt2046Power() override = default;
|
||||
|
||||
std::string getName() const final { return "XPT2046 Power Measurement"; }
|
||||
std::string getDescription() const final { return "Power interface via XPT2046 voltage measurement"; }
|
||||
|
||||
bool supportsMetric(MetricType type) const override;
|
||||
bool getMetric(MetricType type, MetricData& data) override;
|
||||
|
||||
};
|
||||
|
||||
std::shared_ptr<PowerDevice> getOrCreatePower();
|
||||
|
||||
@@ -5,9 +5,6 @@
|
||||
|
||||
#include <esp_err.h>
|
||||
#include <esp_lcd_touch_xpt2046.h>
|
||||
#include <esp_lvgl_port.h>
|
||||
|
||||
Xpt2046Touch* Xpt2046Touch::instance = nullptr;
|
||||
|
||||
bool Xpt2046Touch::createIoHandle(esp_lcd_panel_io_handle_t& outHandle) {
|
||||
const esp_lcd_panel_io_spi_config_t io_config = ESP_LCD_TOUCH_IO_SPI_XPT2046_CONFIG(configuration->spiPinCs);
|
||||
|
||||
@@ -39,8 +39,6 @@ public:
|
||||
|
||||
private:
|
||||
|
||||
static Xpt2046Touch* instance;
|
||||
|
||||
std::unique_ptr<Configuration> configuration;
|
||||
|
||||
bool createIoHandle(esp_lcd_panel_io_handle_t& outHandle) override;
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
#include <nvs_flash.h>
|
||||
#include <rom/ets_sys.h>
|
||||
|
||||
#define TAG "Xpt2046SoftSpi"
|
||||
constexpr auto* TAG = "Xpt2046SoftSpi";
|
||||
|
||||
#define RERUN_CALIBRATE false
|
||||
#define CMD_READ_Y 0x90 // Try different commands if these don't work
|
||||
#define CMD_READ_X 0xD0 // Alternative: 0x98 for Y, 0xD8 for X
|
||||
constexpr auto RERUN_CALIBRATE = false;
|
||||
constexpr auto CMD_READ_Y = 0x90; // Try different commands if these don't work
|
||||
constexpr auto CMD_READ_X = 0xD0; // Alternative: 0x98 for Y, 0xD8 for X
|
||||
|
||||
struct Calibration {
|
||||
int xMin;
|
||||
@@ -33,8 +33,6 @@ Calibration cal = {
|
||||
.yMax = 1900
|
||||
};
|
||||
|
||||
Xpt2046SoftSpi* Xpt2046SoftSpi::instance = nullptr;
|
||||
|
||||
Xpt2046SoftSpi::Xpt2046SoftSpi(std::unique_ptr<Configuration> inConfiguration)
|
||||
: configuration(std::move(inConfiguration)) {
|
||||
assert(configuration != nullptr);
|
||||
@@ -54,62 +52,7 @@ static void ensureNvsInitialized() {
|
||||
initialized = (result == ESP_OK);
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::start(lv_display_t* display) {
|
||||
ensureNvsInitialized();
|
||||
|
||||
TT_LOG_I(TAG, "Starting Xpt2046SoftSpi touch driver");
|
||||
|
||||
// Configure GPIO pins
|
||||
gpio_config_t io_conf = {};
|
||||
|
||||
// Configure MOSI, CLK, CS as outputs
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << configuration->mosiPin) |
|
||||
(1ULL << configuration->clkPin) |
|
||||
(1ULL << configuration->csPin);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
|
||||
if (gpio_config(&io_conf) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure output pins");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure MISO as input
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << configuration->misoPin);
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
|
||||
if (gpio_config(&io_conf) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure input pin");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize pin states
|
||||
gpio_set_level(configuration->csPin, 1); // CS high
|
||||
gpio_set_level(configuration->clkPin, 0); // CLK low
|
||||
gpio_set_level(configuration->mosiPin, 0); // MOSI low
|
||||
|
||||
TT_LOG_I(TAG, "GPIO configured: MOSI=%d, MISO=%d, CLK=%d, CS=%d", configuration->mosiPin, configuration->misoPin, configuration->clkPin, configuration->csPin);
|
||||
|
||||
// Load or perform calibration
|
||||
bool calibrationValid = true; //loadCalibration() && !RERUN_CALIBRATE;
|
||||
if (calibrationValid) {
|
||||
// Check if calibration values are valid (xMin != xMax, yMin != yMax)
|
||||
if (cal.xMin == cal.xMax || cal.yMin == cal.yMax) {
|
||||
TT_LOG_W(TAG, "Invalid calibration detected: xMin=%d, xMax=%d, yMin=%d, yMax=%d", cal.xMin, cal.xMax, cal.yMin, cal.yMax);
|
||||
calibrationValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!calibrationValid) {
|
||||
TT_LOG_W(TAG, "Calibration data not found, invalid, or forced recalibration");
|
||||
calibrate();
|
||||
saveCalibration();
|
||||
} else {
|
||||
TT_LOG_I(TAG, "Loaded calibration: xMin=%d, yMin=%d, xMax=%d, yMax=%d", cal.xMin, cal.yMin, cal.xMax, cal.yMax);
|
||||
}
|
||||
bool Xpt2046SoftSpi::startLvgl(lv_display_t* display) {
|
||||
|
||||
// Create LVGL input device
|
||||
deviceHandle = lv_indev_create();
|
||||
@@ -117,27 +60,24 @@ bool Xpt2046SoftSpi::start(lv_display_t* display) {
|
||||
TT_LOG_E(TAG, "Failed to create LVGL input device");
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(deviceHandle, touchReadCallback);
|
||||
lv_indev_set_user_data(deviceHandle, this);
|
||||
|
||||
instance = this;
|
||||
TT_LOG_I(TAG, "Xpt2046SoftSpi touch driver started successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::stop() {
|
||||
TT_LOG_I(TAG, "Stopping Xpt2046SoftSpi touch driver");
|
||||
instance = nullptr;
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Xpt2046SoftSpi::cleanup() {
|
||||
// Stop LVLG if needed
|
||||
if (deviceHandle != nullptr) {
|
||||
lv_indev_delete(deviceHandle);
|
||||
deviceHandle = nullptr;
|
||||
stopLvgl();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int Xpt2046SoftSpi::readSPI(uint8_t command) {
|
||||
@@ -338,10 +278,64 @@ void Xpt2046SoftSpi::touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data)
|
||||
}
|
||||
}
|
||||
|
||||
// Zero-argument start
|
||||
bool Xpt2046SoftSpi::start() {
|
||||
// Default to LVGL-less startup if needed
|
||||
return startLvgl(nullptr);
|
||||
ensureNvsInitialized();;
|
||||
|
||||
TT_LOG_I(TAG, "Starting Xpt2046SoftSpi touch driver");
|
||||
|
||||
// Configure GPIO pins
|
||||
gpio_config_t io_conf = {};
|
||||
|
||||
// Configure MOSI, CLK, CS as outputs
|
||||
io_conf.intr_type = GPIO_INTR_DISABLE;
|
||||
io_conf.mode = GPIO_MODE_OUTPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << configuration->mosiPin) |
|
||||
(1ULL << configuration->clkPin) |
|
||||
(1ULL << configuration->csPin);
|
||||
io_conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
io_conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
|
||||
if (gpio_config(&io_conf) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure output pins");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure MISO as input
|
||||
io_conf.mode = GPIO_MODE_INPUT;
|
||||
io_conf.pin_bit_mask = (1ULL << configuration->misoPin);
|
||||
io_conf.pull_up_en = GPIO_PULLUP_ENABLE;
|
||||
|
||||
if (gpio_config(&io_conf) != ESP_OK) {
|
||||
TT_LOG_E(TAG, "Failed to configure input pin");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize pin states
|
||||
gpio_set_level(configuration->csPin, 1); // CS high
|
||||
gpio_set_level(configuration->clkPin, 0); // CLK low
|
||||
gpio_set_level(configuration->mosiPin, 0); // MOSI low
|
||||
|
||||
TT_LOG_I(TAG, "GPIO configured: MOSI=%d, MISO=%d, CLK=%d, CS=%d", configuration->mosiPin, configuration->misoPin, configuration->clkPin, configuration->csPin);
|
||||
|
||||
// Load or perform calibration
|
||||
bool calibrationValid = true; //loadCalibration() && !RERUN_CALIBRATE;
|
||||
if (calibrationValid) {
|
||||
// Check if calibration values are valid (xMin != xMax, yMin != yMax)
|
||||
if (cal.xMin == cal.xMax || cal.yMin == cal.yMax) {
|
||||
TT_LOG_W(TAG, "Invalid calibration detected: xMin=%d, xMax=%d, yMin=%d, yMax=%d", cal.xMin, cal.xMax, cal.yMin, cal.yMax);
|
||||
calibrationValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!calibrationValid) {
|
||||
TT_LOG_W(TAG, "Calibration data not found, invalid, or forced recalibration");
|
||||
calibrate();
|
||||
saveCalibration();
|
||||
} else {
|
||||
TT_LOG_I(TAG, "Loaded calibration: xMin=%d, yMin=%d, xMax=%d, yMax=%d", cal.xMin, cal.yMin, cal.xMax, cal.yMax);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Whether this device supports LVGL
|
||||
@@ -349,19 +343,12 @@ bool Xpt2046SoftSpi::supportsLvgl() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Start with LVGL display
|
||||
bool Xpt2046SoftSpi::startLvgl(lv_display_t* display) {
|
||||
return start(display);
|
||||
}
|
||||
|
||||
// Stop LVGL
|
||||
bool Xpt2046SoftSpi::stopLvgl() {
|
||||
cleanup();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Supports a separate touch driver? Yes/No
|
||||
bool Xpt2046SoftSpi::supportsTouchDriver() {
|
||||
if (deviceHandle != nullptr) {
|
||||
lv_indev_delete(deviceHandle);
|
||||
deviceHandle = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,8 @@
|
||||
|
||||
#include "Tactility/hal/touch/TouchDevice.h"
|
||||
#include "Tactility/hal/touch/TouchDriver.h"
|
||||
#include <Tactility/TactilityCore.h>
|
||||
#include "lvgl.h"
|
||||
#include <driver/gpio.h>
|
||||
#include <esp_err.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/task.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
@@ -61,12 +57,10 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
static Xpt2046SoftSpi* instance;
|
||||
std::unique_ptr<Configuration> configuration;
|
||||
lv_indev_t* deviceHandle = nullptr;
|
||||
|
||||
int readSPI(uint8_t command);
|
||||
void cleanup();
|
||||
bool loadCalibration();
|
||||
void saveCalibration();
|
||||
static void touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data);
|
||||
@@ -78,24 +72,20 @@ public:
|
||||
std::string getName() const final { return "Xpt2046SoftSpi"; }
|
||||
std::string getDescription() const final { return "Xpt2046 Soft SPI touch driver"; }
|
||||
|
||||
bool start() override; // zero-arg start
|
||||
bool start() override;
|
||||
bool stop() override;
|
||||
|
||||
bool supportsLvgl() const override;
|
||||
bool startLvgl(lv_display_t* display) override;
|
||||
bool stopLvgl() override;
|
||||
bool stop() override;
|
||||
bool supportsTouchDriver() override;
|
||||
|
||||
bool supportsTouchDriver() override { return true; }
|
||||
std::shared_ptr<tt::hal::touch::TouchDriver> getTouchDriver() override;
|
||||
lv_indev_t* getLvglIndev() override { return deviceHandle; }
|
||||
|
||||
// Original LVGL-specific start
|
||||
bool start(lv_display_t* display);
|
||||
|
||||
// XPT2046-specific methods
|
||||
Point getTouch();
|
||||
void calibrate();
|
||||
void setCalibration(int xMin, int yMin, int xMax, int yMax);
|
||||
bool isTouched();
|
||||
|
||||
// Static instance access
|
||||
static Xpt2046SoftSpi* getInstance() { return instance; }
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user