Merge develop into main (#321)
- Implemented `TouchDriver` for `Xpt2046SoftSpi` - Refactored system initialization
This commit is contained in:
committed by
GitHub
parent
65335578a4
commit
457c21ffd8
@@ -68,7 +68,7 @@ bool EspLcdDisplay::startLvgl() {
|
||||
}
|
||||
|
||||
auto touch_device = getTouchDevice();
|
||||
if (touch_device != nullptr) {
|
||||
if (touch_device != nullptr && touch_device->supportsLvgl()) {
|
||||
touch_device->startLvgl(lvglDisplay);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,20 +52,63 @@ static void ensureNvsInitialized() {
|
||||
initialized = (result == ESP_OK);
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::startLvgl(lv_display_t* display) {
|
||||
bool Xpt2046SoftSpi::start() {
|
||||
ensureNvsInitialized();
|
||||
|
||||
// Create LVGL input device
|
||||
deviceHandle = lv_indev_create();
|
||||
if (!deviceHandle) {
|
||||
TT_LOG_E(TAG, "Failed to create LVGL input device");
|
||||
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;
|
||||
}
|
||||
|
||||
lv_indev_set_type(deviceHandle, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(deviceHandle, touchReadCallback);
|
||||
lv_indev_set_user_data(deviceHandle, this);
|
||||
// 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);
|
||||
}
|
||||
|
||||
TT_LOG_I(TAG, "Xpt2046SoftSpi touch driver started successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -73,13 +116,41 @@ bool Xpt2046SoftSpi::stop() {
|
||||
TT_LOG_I(TAG, "Stopping Xpt2046SoftSpi touch driver");
|
||||
|
||||
// Stop LVLG if needed
|
||||
if (deviceHandle != nullptr) {
|
||||
if (lvglDevice != nullptr) {
|
||||
stopLvgl();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::startLvgl(lv_display_t* display) {
|
||||
if (lvglDevice != nullptr) {
|
||||
TT_LOG_E(TAG, "LVGL was already started");
|
||||
return false;
|
||||
}
|
||||
|
||||
lvglDevice = lv_indev_create();
|
||||
if (!lvglDevice) {
|
||||
TT_LOG_E(TAG, "Failed to create LVGL input device");
|
||||
return false;
|
||||
}
|
||||
|
||||
lv_indev_set_type(lvglDevice, LV_INDEV_TYPE_POINTER);
|
||||
lv_indev_set_read_cb(lvglDevice, touchReadCallback);
|
||||
lv_indev_set_user_data(lvglDevice, this);
|
||||
|
||||
TT_LOG_I(TAG, "Xpt2046SoftSpi touch driver started successfully");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::stopLvgl() {
|
||||
if (lvglDevice != nullptr) {
|
||||
lv_indev_delete(lvglDevice);
|
||||
lvglDevice = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int Xpt2046SoftSpi::readSPI(uint8_t command) {
|
||||
int result = 0;
|
||||
|
||||
@@ -186,12 +257,14 @@ void Xpt2046SoftSpi::setCalibration(int xMin, int yMin, int xMax, int yMax) {
|
||||
TT_LOG_I(TAG, "Manual calibration set: xMin=%d, yMin=%d, xMax=%d, yMax=%d", xMin, yMin, xMax, yMax);
|
||||
}
|
||||
|
||||
Point Xpt2046SoftSpi::getTouch() {
|
||||
bool Xpt2046SoftSpi::getTouchPoint(Point& point) {
|
||||
|
||||
const int samples = 8; // More samples for better accuracy
|
||||
int totalX = 0, totalY = 0;
|
||||
int validSamples = 0;
|
||||
|
||||
gpio_set_level(configuration->csPin, 0);
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int rawX = readSPI(CMD_READ_X);
|
||||
int rawY = readSPI(CMD_READ_Y);
|
||||
@@ -206,8 +279,10 @@ Point Xpt2046SoftSpi::getTouch() {
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
|
||||
gpio_set_level(configuration->csPin, 1);
|
||||
|
||||
if (validSamples == 0) {
|
||||
return Point {0, 0};
|
||||
return false;
|
||||
}
|
||||
|
||||
int rawX = totalX / validSamples;
|
||||
@@ -218,7 +293,7 @@ Point Xpt2046SoftSpi::getTouch() {
|
||||
|
||||
if (xRange <= 0 || yRange <= 0) {
|
||||
TT_LOG_W(TAG, "Invalid calibration: xRange=%d, yRange=%d", xRange, yRange);
|
||||
return Point {0, 0};
|
||||
return false;
|
||||
}
|
||||
|
||||
int x = (rawX - cal.xMin) * configuration->xMax / xRange;
|
||||
@@ -228,17 +303,20 @@ Point Xpt2046SoftSpi::getTouch() {
|
||||
if (configuration->mirrorX) x = configuration->xMax - x;
|
||||
if (configuration->mirrorY) y = configuration->yMax - y;
|
||||
|
||||
x = std::clamp(x, 0, (int)configuration->xMax);
|
||||
y = std::clamp(y, 0, (int)configuration->yMax);
|
||||
point.x = std::clamp(x, 0, (int)configuration->xMax);
|
||||
point.y = std::clamp(y, 0, (int)configuration->yMax);
|
||||
|
||||
return Point {x, y};
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: Merge isTouched() and getTouchPoint() into 1 method
|
||||
bool Xpt2046SoftSpi::isTouched() {
|
||||
const int samples = 3;
|
||||
int xTotal = 0, yTotal = 0;
|
||||
int validSamples = 0;
|
||||
|
||||
gpio_set_level(configuration->csPin, 0);
|
||||
|
||||
for (int i = 0; i < samples; i++) {
|
||||
int x = readSPI(CMD_READ_X);
|
||||
int y = readSPI(CMD_READ_Y);
|
||||
@@ -259,7 +337,7 @@ bool Xpt2046SoftSpi::isTouched() {
|
||||
|
||||
// Debug logging (remove this once working)
|
||||
if (touched) {
|
||||
TT_LOG_I(TAG, "Touch detected: validSamples=%d, avgX=%d, avgY=%d", validSamples, xTotal / validSamples, yTotal / validSamples);
|
||||
TT_LOG_D(TAG, "Touch detected: validSamples=%d, avgX=%d, avgY=%d", validSamples, xTotal / validSamples, yTotal / validSamples);
|
||||
}
|
||||
|
||||
return touched;
|
||||
@@ -268,8 +346,8 @@ bool Xpt2046SoftSpi::isTouched() {
|
||||
void Xpt2046SoftSpi::touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data) {
|
||||
Xpt2046SoftSpi* touch = static_cast<Xpt2046SoftSpi*>(lv_indev_get_user_data(indev));
|
||||
|
||||
if (touch && touch->isTouched()) {
|
||||
Point point = touch->getTouch();
|
||||
Point point;
|
||||
if (touch && touch->isTouched() && touch->getTouchPoint(point)) {
|
||||
data->point.x = point.x;
|
||||
data->point.y = point.y;
|
||||
data->state = LV_INDEV_STATE_PRESSED;
|
||||
@@ -278,81 +356,13 @@ void Xpt2046SoftSpi::touchReadCallback(lv_indev_t* indev, lv_indev_data_t* data)
|
||||
}
|
||||
}
|
||||
|
||||
bool Xpt2046SoftSpi::start() {
|
||||
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
|
||||
bool Xpt2046SoftSpi::supportsLvgl() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Stop LVGL
|
||||
bool Xpt2046SoftSpi::stopLvgl() {
|
||||
if (deviceHandle != nullptr) {
|
||||
lv_indev_delete(deviceHandle);
|
||||
deviceHandle = nullptr;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return driver instance if any
|
||||
std::shared_ptr<tt::hal::touch::TouchDriver> Xpt2046SoftSpi::getTouchDriver() {
|
||||
return nullptr; // replace with actual driver later
|
||||
assert(lvglDevice == nullptr); // Still attached to LVGL context. Call stopLvgl() first.
|
||||
|
||||
if (touchDriver == nullptr) {
|
||||
touchDriver = std::make_shared<Xpt2046SoftSpiDriver>(this);
|
||||
}
|
||||
|
||||
return touchDriver;
|
||||
}
|
||||
|
||||
@@ -57,8 +57,28 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
class Xpt2046SoftSpiDriver final : public tt::hal::touch::TouchDriver {
|
||||
Xpt2046SoftSpi* device;
|
||||
public:
|
||||
Xpt2046SoftSpiDriver(Xpt2046SoftSpi* device) : device(device) {}
|
||||
bool getTouchedPoints(uint16_t* x, uint16_t* y, uint16_t* strength, uint8_t* pointCount, uint8_t maxPointCount) override {
|
||||
Point point;
|
||||
if (device->isTouched() && device->getTouchPoint(point)) {
|
||||
*x = point.x;
|
||||
*y = point.y;
|
||||
*pointCount = 1;
|
||||
return true;
|
||||
} else {
|
||||
*pointCount = 0;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::unique_ptr<Configuration> configuration;
|
||||
lv_indev_t* deviceHandle = nullptr;
|
||||
lv_indev_t* lvglDevice = nullptr;
|
||||
std::shared_ptr<tt::hal::touch::TouchDriver> touchDriver;
|
||||
|
||||
int readSPI(uint8_t command);
|
||||
bool loadCalibration();
|
||||
@@ -75,16 +95,16 @@ public:
|
||||
bool start() override;
|
||||
bool stop() override;
|
||||
|
||||
bool supportsLvgl() const override;
|
||||
bool supportsLvgl() const override { return true; }
|
||||
bool startLvgl(lv_display_t* display) override;
|
||||
bool stopLvgl() override;
|
||||
|
||||
bool supportsTouchDriver() override { return true; }
|
||||
std::shared_ptr<tt::hal::touch::TouchDriver> getTouchDriver() override;
|
||||
lv_indev_t* getLvglIndev() override { return deviceHandle; }
|
||||
lv_indev_t* getLvglIndev() override { return lvglDevice; }
|
||||
|
||||
// XPT2046-specific methods
|
||||
Point getTouch();
|
||||
bool getTouchPoint(Point& point);
|
||||
void calibrate();
|
||||
void setCalibration(int xMin, int yMin, int xMax, int yMax);
|
||||
bool isTouched();
|
||||
|
||||
Reference in New Issue
Block a user