SPI device migration (#490)
- Implement SPI devices in dts files for all devices - Removed `tt::hal::spi` HAL and its configurations - Fix for devicetree generator "boolean" support - Remove unused custom locks in all `DisplayDevice` implementations - Fixed some bugs with devices - Updated XPT2046 driver - Fix for `WifiEsp` deadlock - Export a lot of new `math.h` symbols with `tt_init.cpp` - Created `SpiDeviceLock` in `TactilityCore` as a wrapper for kernel SPI locking - Improved `TactilityKernel` SPI driver.
This commit is contained in:
committed by
GitHub
parent
74127a5f6c
commit
d27404964a
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/sdcard/SdCardDevice.h>
|
||||
#include <Tactility/hal/spi/Spi.h>
|
||||
|
||||
namespace tt::hal {
|
||||
|
||||
@@ -11,11 +10,6 @@ typedef std::vector<std::shared_ptr<Device>> DeviceVector;
|
||||
|
||||
typedef std::shared_ptr<Device> (*CreateDevice)();
|
||||
|
||||
enum class LvglInit {
|
||||
Default,
|
||||
None
|
||||
};
|
||||
|
||||
/** Affects LVGL widget style */
|
||||
enum class UiScale {
|
||||
/** Ideal for very small non-touch screen devices (e.g. Waveshare S3 LCD 1.3") */
|
||||
@@ -26,21 +20,14 @@ enum class UiScale {
|
||||
|
||||
struct Configuration {
|
||||
/**
|
||||
* Called before I2C/SPI/etc is initialized.
|
||||
* Used for powering on the peripherals manually.
|
||||
*/
|
||||
const InitBoot initBoot = nullptr;
|
||||
|
||||
/** Init behaviour: default (esp_lvgl_port for ESP32, nothing for PC) or None (nothing on any platform). Only used in Tactility, not in TactilityHeadless. */
|
||||
const LvglInit lvglInit = LvglInit::Default;
|
||||
|
||||
/** Modify LVGL widget size */
|
||||
const UiScale uiScale = UiScale::Default;
|
||||
|
||||
std::function<DeviceVector()> createDevices = [] { return std::vector<std::shared_ptr<Device>>(); };
|
||||
|
||||
/** A list of SPI interface configurations */
|
||||
const std::vector<spi::Configuration> spi = {};
|
||||
const std::function<DeviceVector()> createDevices = [] { return DeviceVector(); };
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -24,7 +24,6 @@ public:
|
||||
virtual uint16_t getPixelWidth() const = 0;
|
||||
virtual uint16_t getPixelHeight() const = 0;
|
||||
virtual bool drawBitmap(int xStart, int yStart, int xEnd, int yEnd, const void* pixelData) = 0;
|
||||
virtual std::shared_ptr<Lock> getLock() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
#include <tactility/hal/Device.h>
|
||||
#include <Tactility/hal/spi/Spi.h>
|
||||
#include <sd_protocol_types.h>
|
||||
#include <soc/gpio_num.h>
|
||||
#include <utility>
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "SdCardDevice.h"
|
||||
#include "Tactility/kernel/SpiDeviceLock.h"
|
||||
|
||||
#include <Tactility/hal/spi/Spi.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <driver/spi_common.h>
|
||||
|
||||
#include <sd_protocol_types.h>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <hal/spi_types.h>
|
||||
#include <soc/gpio_num.h>
|
||||
|
||||
namespace tt::hal::sdcard {
|
||||
|
||||
@@ -64,15 +64,23 @@ private:
|
||||
std::string mountPath;
|
||||
sdmmc_card_t* card = nullptr;
|
||||
std::shared_ptr<Config> config;
|
||||
std::shared_ptr<Lock> lock;
|
||||
|
||||
bool applyGpioWorkAround();
|
||||
bool mountInternal(const std::string& mountPath);
|
||||
|
||||
public:
|
||||
|
||||
explicit SpiSdCardDevice(std::unique_ptr<Config> config) : SdCardDevice(config->mountBehaviourAtBoot),
|
||||
config(std::move(config))
|
||||
{}
|
||||
explicit SpiSdCardDevice(std::unique_ptr<Config> newConfig, ::Device* spiController) : SdCardDevice(newConfig->mountBehaviourAtBoot),
|
||||
config(std::move(newConfig))
|
||||
{
|
||||
if (config->customLock == nullptr) {
|
||||
auto spi_lock = std::make_shared<SpiDeviceLock>(spiController);
|
||||
lock = std::static_pointer_cast<Lock>(spi_lock);
|
||||
} else {
|
||||
lock = config->customLock;
|
||||
}
|
||||
}
|
||||
|
||||
std::string getName() const override { return "SD Card"; }
|
||||
std::string getDescription() const override { return "SD card via SPI interface"; }
|
||||
@@ -82,11 +90,7 @@ public:
|
||||
std::string getMountPath() const override { return mountPath; }
|
||||
|
||||
std::shared_ptr<Lock> getLock() const override {
|
||||
if (config->customLock != nullptr) {
|
||||
return config->customLock;
|
||||
} else {
|
||||
return spi::getLock(config->spiHost);
|
||||
}
|
||||
return lock;
|
||||
}
|
||||
|
||||
State getState(TickType_t timeout) const override;
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "SpiCompat.h"
|
||||
|
||||
#include <Tactility/Lock.h>
|
||||
#include <Tactility/freertoscompat/RTOS.h>
|
||||
|
||||
namespace tt::hal::spi {
|
||||
|
||||
constexpr TickType_t defaultTimeout = 10 / portTICK_PERIOD_MS;
|
||||
|
||||
enum class InitMode {
|
||||
ByTactility, // Tactility will initialize it in the correct bootup phase
|
||||
ByExternal, // The device is already initialized and Tactility should assume it works
|
||||
Disabled // Not initialized by default
|
||||
};
|
||||
|
||||
struct Configuration {
|
||||
spi_host_device_t device;
|
||||
spi_common_dma_t dma;
|
||||
spi_bus_config_t config;
|
||||
/** Whether this bus should be initialized when device starts up */
|
||||
InitMode initMode;
|
||||
/** Whether configuration can be changed. */
|
||||
bool isMutable;
|
||||
/** Optional custom lock - otherwise creates one internally */
|
||||
std::shared_ptr<Lock> lock;
|
||||
};
|
||||
|
||||
enum class Status {
|
||||
Started,
|
||||
Stopped,
|
||||
Unknown
|
||||
};
|
||||
|
||||
/** Start communications */
|
||||
bool start(spi_host_device_t device);
|
||||
|
||||
/** Stop communications */
|
||||
bool stop(spi_host_device_t device);
|
||||
|
||||
/** @return true if communications were started successfully */
|
||||
bool isStarted(spi_host_device_t device);
|
||||
|
||||
/**
|
||||
* Return the lock for the specified SPI device. Never returns nullptr.
|
||||
* @return the lock that represents the specified device. Can be used with third party SPI implementations or native API calls (e.g. ESP-IDF).
|
||||
*/
|
||||
std::shared_ptr<Lock> getLock(spi_host_device_t device);
|
||||
|
||||
} // namespace tt::hal::spi
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../gpio/Gpio.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include <driver/spi_common.h>
|
||||
#else
|
||||
|
||||
#define SPI_HOST_MAX 3
|
||||
|
||||
typedef tt::hal::gpio::Pin gpio_num_t;
|
||||
|
||||
typedef int spi_host_device_t;
|
||||
struct spi_bus_config_t {
|
||||
gpio_num_t miso_io_num;
|
||||
gpio_num_t mosi_io_num;
|
||||
gpio_num_t sclk_io_num;
|
||||
};
|
||||
struct spi_common_dma_t {};
|
||||
|
||||
#endif
|
||||
@@ -1,17 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <Tactility/hal/spi/Spi.h>
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
namespace tt::hal::spi {
|
||||
|
||||
/**
|
||||
* Called by main HAL init to ready the internal state of the SPI HAL.
|
||||
* @param[in] configurations HAL configuration for a board
|
||||
* @return true on success
|
||||
*/
|
||||
bool init(const std::vector<Configuration>& configurations);
|
||||
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <tactility/check.h>
|
||||
#include <Tactility/hal/Configuration.h>
|
||||
#include <tactility/hal/Device.h>
|
||||
#include <Tactility/hal/spi/SpiInit.h>
|
||||
|
||||
#include <Tactility/hal/display/DisplayDevice.h>
|
||||
#include <Tactility/hal/sdcard/SdCardMounting.h>
|
||||
@@ -64,8 +63,6 @@ static void startDisplays() {
|
||||
void init(const Configuration& configuration) {
|
||||
kernel::publishSystemEvent(kernel::SystemEvent::BootInitHalBegin);
|
||||
|
||||
check(spi::init(configuration.spi), "SPI init failed");
|
||||
|
||||
if (configuration.initBoot != nullptr) {
|
||||
check(configuration.initBoot(), "Init boot failed");
|
||||
}
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
#include <Tactility/hal/spi/Spi.h>
|
||||
|
||||
#include <Tactility/Logger.h>
|
||||
#include <Tactility/RecursiveMutex.h>
|
||||
|
||||
namespace tt::hal::spi {
|
||||
|
||||
static const auto LOGGER = Logger("SPI");
|
||||
|
||||
struct Data {
|
||||
std::shared_ptr<Lock> lock;
|
||||
bool isConfigured = false;
|
||||
bool isStarted = false;
|
||||
Configuration configuration;
|
||||
};
|
||||
|
||||
static Data dataArray[SPI_HOST_MAX];
|
||||
|
||||
bool init(const std::vector<Configuration>& configurations) {
|
||||
LOGGER.info("Init");
|
||||
for (const auto& configuration: configurations) {
|
||||
Data& data = dataArray[configuration.device];
|
||||
data.configuration = configuration;
|
||||
data.isConfigured = true;
|
||||
if (configuration.lock != nullptr) {
|
||||
data.lock = configuration.lock;
|
||||
} else {
|
||||
data.lock = std::make_shared<RecursiveMutex>();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& config: configurations) {
|
||||
if (config.initMode == InitMode::ByTactility) {
|
||||
if (!start(config.device)) {
|
||||
return false;
|
||||
}
|
||||
} else if (config.initMode == InitMode::ByExternal) {
|
||||
dataArray[config.device].isStarted = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool configure(spi_host_device_t device, const spi_bus_config_t& configuration) {
|
||||
auto lock = getLock(device)->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
Data& data = dataArray[device];
|
||||
if (data.isStarted) {
|
||||
LOGGER.error("({}) Cannot reconfigure while interface is started", static_cast<int>(device));
|
||||
return false;
|
||||
} else if (!data.configuration.isMutable) {
|
||||
LOGGER.error("({}) Mutation not allowed by original configuration", static_cast<int>(device));
|
||||
return false;
|
||||
} else {
|
||||
data.configuration.config = configuration;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool start(spi_host_device_t device) {
|
||||
auto lock = getLock(device)->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
Data& data = dataArray[device];
|
||||
|
||||
if (data.isStarted) {
|
||||
LOGGER.error("({}) Starting: Already started", static_cast<int>(device));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.isConfigured) {
|
||||
LOGGER.error("({}) Starting: Not configured", static_cast<int>(device));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
auto result = spi_bus_initialize(device, &data.configuration.config, data.configuration.dma);
|
||||
if (result != ESP_OK) {
|
||||
LOGGER.error("({}) Starting: Failed to initialize: {}", static_cast<int>(device), esp_err_to_name(result));
|
||||
return false;
|
||||
} else {
|
||||
data.isStarted = true;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
data.isStarted = true;
|
||||
|
||||
#endif
|
||||
|
||||
LOGGER.info("({}) Started", static_cast<int>(device));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool stop(spi_host_device_t device) {
|
||||
auto lock = getLock(device)->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
Data& data = dataArray[device];
|
||||
Configuration& config = data.configuration;
|
||||
|
||||
if (!config.isMutable) {
|
||||
LOGGER.error("({}) Stopping: Not allowed, immutable", static_cast<int>(device));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data.isStarted) {
|
||||
LOGGER.error("({}) Stopping: Not started", static_cast<int>(device));
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
|
||||
auto result = spi_bus_free(device);
|
||||
if (result != ESP_OK) {
|
||||
LOGGER.error("({}) Stopping: Failed to free device: {}", static_cast<int>(device), esp_err_to_name(result));
|
||||
return false;
|
||||
} else {
|
||||
data.isStarted = false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
data.isStarted = false;
|
||||
|
||||
#endif
|
||||
|
||||
LOGGER.info("({}) Stopped", static_cast<int>(device));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool isStarted(spi_host_device_t device) {
|
||||
auto lock = getLock(device)->asScopedLock();
|
||||
lock.lock();
|
||||
|
||||
return dataArray[device].isStarted;
|
||||
}
|
||||
|
||||
std::shared_ptr<Lock> getLock(spi_host_device_t device) {
|
||||
return dataArray[device].lock;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -47,8 +47,8 @@ static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi);
|
||||
class Wifi {
|
||||
|
||||
std::atomic<RadioState> radio_state = RadioState::Off;
|
||||
bool scan_active = false;
|
||||
bool secure_connection = false;
|
||||
std::atomic<bool> scan_active = false;
|
||||
std::atomic<bool> secure_connection = false;
|
||||
|
||||
public:
|
||||
|
||||
@@ -81,54 +81,34 @@ public:
|
||||
kernel::SystemEventSubscription bootEventSubscription = kernel::NoSystemEventSubscription;
|
||||
|
||||
RadioState getRadioState() const {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
// TODO: Handle lock failure
|
||||
return radio_state;
|
||||
}
|
||||
|
||||
void setRadioState(RadioState newState) {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
// TODO: Handle lock failure
|
||||
radio_state = newState;
|
||||
}
|
||||
|
||||
bool isScanning() const {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
// TODO: Handle lock failure
|
||||
return scan_active;
|
||||
}
|
||||
|
||||
void setScanning(bool newState) {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
// TODO: Handle lock failure
|
||||
scan_active = newState;
|
||||
}
|
||||
|
||||
bool isScanActive() const {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
return scan_active;
|
||||
}
|
||||
|
||||
void setScanActive(bool newState) {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
scan_active = newState;
|
||||
}
|
||||
|
||||
bool isSecureConnection() const {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
return secure_connection;
|
||||
}
|
||||
|
||||
void setSecureConnection(bool newState) {
|
||||
auto lock = dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
secure_connection = newState;
|
||||
}
|
||||
};
|
||||
@@ -324,11 +304,6 @@ bool isConnectionSecure() {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto lock = wifi->dataMutex.asScopedLock();
|
||||
if (!lock.lock(10 / portTICK_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return wifi->isSecureConnection();
|
||||
}
|
||||
|
||||
@@ -878,7 +853,7 @@ static void dispatchDisconnectButKeepActive(std::shared_ptr<Wifi> wifi) {
|
||||
|
||||
static bool shouldScanForAutoConnect(std::shared_ptr<Wifi> wifi) {
|
||||
auto lock = wifi->dataMutex.asScopedLock();
|
||||
if (!lock.lock(100)) {
|
||||
if (!lock.lock(100 / portTICK_PERIOD_MS)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -912,8 +887,12 @@ void onAutoConnectTimer() {
|
||||
std::string getIp() {
|
||||
auto wifi = std::static_pointer_cast<Wifi>(wifi_singleton);
|
||||
|
||||
if (wifi == nullptr) return "127.0.0.1";
|
||||
|
||||
auto lock = wifi->dataMutex.asScopedLock();
|
||||
lock.lock();
|
||||
if (!lock.lock(100 / portTICK_PERIOD_MS)) {
|
||||
return "127.0.0.1";
|
||||
}
|
||||
|
||||
return std::format("{}.{}.{}.{}", IP2STR(&wifi->ip_info.ip));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user