This commit is contained in:
Ken Van Hoeylandt 2026-06-21 20:07:20 +02:00
parent 4909b7075b
commit fb6f1c31d2
24 changed files with 103 additions and 273 deletions

View File

@ -45,8 +45,8 @@
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 12 GPIO_FLAG_NONE>, // Display
<&gpio0 9 GPIO_FLAG_NONE>, // Radio
<&gpio0 39 GPIO_FLAG_NONE>; // SD card
<&gpio0 39 GPIO_FLAG_NONE>, // SD card
<&gpio0 9 GPIO_FLAG_NONE>; // Radio
pin-mosi = <&gpio0 41 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 38 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 40 GPIO_FLAG_NONE>;
@ -55,8 +55,9 @@
compatible = "display-placeholder";
};
sdcard@2 {
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};

View File

@ -35,20 +35,21 @@
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 21 GPIO_FLAG_NONE>, // SD card
<&gpio0 36 GPIO_FLAG_NONE>; // Display
cs-gpios = <&gpio0 36 GPIO_FLAG_NONE>, // Display
<&gpio0 21 GPIO_FLAG_NONE>; // SD card
pin-mosi = <&gpio0 34 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 33 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 35 GPIO_FLAG_NONE>;
sdcard@0 {
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
};
display@1 {
display@0 {
compatible = "display-placeholder";
};
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};
// ES8311

View File

@ -53,20 +53,21 @@
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 4 GPIO_FLAG_NONE>, // SD card
<&gpio0 5 GPIO_FLAG_NONE>; // Display
cs-gpios = <&gpio0 5 GPIO_FLAG_NONE>, // Display
<&gpio0 4 GPIO_FLAG_NONE>; // SD card
pin-mosi = <&gpio0 23 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 38 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 18 GPIO_FLAG_NONE>;
sdcard@0 {
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
};
display@1 {
display@0 {
compatible = "display-placeholder";
};
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};
// NS4168: Speaker and microphone

View File

@ -78,20 +78,21 @@
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 4 GPIO_FLAG_NONE>, // SD card
<&gpio0 3 GPIO_FLAG_NONE>; // Display
cs-gpios = <&gpio0 3 GPIO_FLAG_NONE>, // Display
<&gpio0 4 GPIO_FLAG_NONE>; // SD card
pin-mosi = <&gpio0 37 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 35 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>;
sdcard@0 {
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
};
display@1 {
display@0 {
compatible = "display-placeholder";
};
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};
// TODO: Enable speaker via ES7210 I2C: https://github.com/m5stack/M5Unified/blob/a6256725481f1bc366655fa48cf03b6095e30ad1/src/M5Unified.cpp#L417

View File

@ -112,19 +112,20 @@
spi0 {
compatible = "espressif,esp32-spi";
host = <SPI2_HOST>;
cs-gpios = <&gpio0 4 GPIO_FLAG_NONE>, // SD card
<&gpio0 3 GPIO_FLAG_NONE>; // Display
cs-gpios = <&gpio0 3 GPIO_FLAG_NONE>, // Display
<&gpio0 4 GPIO_FLAG_NONE>; // SD card
pin-mosi = <&gpio0 37 GPIO_FLAG_NONE>;
pin-miso = <&gpio0 35 GPIO_FLAG_NONE>;
pin-sclk = <&gpio0 36 GPIO_FLAG_NONE>;
sdcard@0 {
compatible = "espressif,esp32-sdspi";
frequency-khz = <20000>;
display@0 {
compatible = "display-placeholder";
};
display@1 {
compatible = "display-placeholder";
sdcard@1 {
compatible = "espressif,esp32-sdspi";
status = "disabled"; // Must be started after display
frequency-khz = <20000>;
};
};

View File

@ -1,9 +1,7 @@
#include "hal/SdlDisplay.h"
#include "hal/SdlKeyboard.h"
#include "hal/SimulatorPower.h"
#include "hal/SimulatorSdCard.h"
#include <src/lv_init.h> // LVGL
#include <Tactility/hal/Configuration.h>
#define TAG "hardware"
@ -15,7 +13,6 @@ static std::vector<std::shared_ptr<tt::hal::Device>> createDevices() {
std::make_shared<SdlDisplay>(),
std::make_shared<SdlKeyboard>(),
std::make_shared<SimulatorPower>(),
std::make_shared<SimulatorSdCard>()
};
}

View File

@ -1,42 +0,0 @@
#pragma once
#include "Tactility/hal/sdcard/SdCardDevice.h"
#include <Tactility/RecursiveMutex.h>
#include <memory>
using tt::hal::sdcard::SdCardDevice;
class SimulatorSdCard final : public SdCardDevice {
State state;
std::shared_ptr<tt::Lock> lock;
std::string mountPath;
public:
SimulatorSdCard() : SdCardDevice(MountBehaviour::AtBoot),
state(State::Unmounted),
lock(std::make_shared<tt::RecursiveMutex>())
{}
std::string getName() const override { return "Mock SD Card"; }
std::string getDescription() const override { return ""; }
bool mount(const std::string& newMountPath) override {
state = State::Mounted;
mountPath = newMountPath;
return true;
}
bool unmount() override {
state = State::Unmounted;
mountPath = "";
return true;
}
std::string getMountPath() const override { return mountPath; }
std::shared_ptr<tt::Lock> getLock() const override { return lock; }
State getState(TickType_t timeout) const override { return state; }
};

View File

@ -10,6 +10,7 @@
#include <tactility/drivers/esp32_sdmmc.h>
#include <tactility/drivers/esp32_sdmmc_fs.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/sdcard.h>
#include <tactility/filesystem/file_system.h>
#include <tactility/log.h>
@ -177,7 +178,7 @@ Driver esp32_sdmmc_driver = {
.start_device = start,
.stop_device = stop,
.api = nullptr,
.device_type = nullptr,
.device_type = &SDCARD_TYPE,
.owner = &platform_esp32_module,
.internal = nullptr
};

View File

@ -10,6 +10,7 @@
#include <tactility/drivers/esp32_spi.h>
#include <tactility/drivers/gpio_descriptor.h>
#include <tactility/drivers/spi_controller.h>
#include <tactility/drivers/sdcard.h>
#include <tactility/filesystem/file_system.h>
#include <tactility/log.h>
@ -165,7 +166,7 @@ Driver esp32_sdspi_driver = {
.start_device = start,
.stop_device = stop,
.api = nullptr,
.device_type = nullptr,
.device_type = &SDCARD_TYPE,
.owner = &platform_esp32_module,
.internal = nullptr
};

View File

@ -1,84 +0,0 @@
#pragma once
#include <tactility/hal/Device.h>
#include <Tactility/Lock.h>
#include <Tactility/TactilityCore.h>
struct FileSystem;
namespace tt::hal::sdcard {
/**
* Warning: getLock() does not have to be used when calling any of the functions of this class.
* The lock is only used for file access on the path where the SD card is mounted.
* This is mainly used when accessing the SD card on a shared SPI bus.
*/
class SdCardDevice : public Device {
public:
enum class State {
Mounted,
Unmounted,
Error,
Timeout // Failed to retrieve state due to timeout
};
enum class MountBehaviour {
AtBoot, /** Only mount at boot */
Anytime /** Mount/dismount any time */
};
private:
MountBehaviour mountBehaviour;
FileSystem* fileSystem;
public:
explicit SdCardDevice(MountBehaviour mountBehaviour);
~SdCardDevice() override;
Type getType() const final { return Type::SdCard; };
/**
* Mount the device.
* @param mountPath the path to mount at
* @return true on successful mount
*/
virtual bool mount(const std::string& mountPath) = 0;
/**
* Unmount the device.
* @return true on successful unmount
*/
virtual bool unmount() = 0;
virtual State getState(TickType_t timeout = kernel::MAX_TICKS) const = 0;
/** @return empty string when not mounted or the mount path if mounted */
virtual std::string getMountPath() const = 0;
/** @return non-null lock, used by code that wants to access files on the mount path of this SD card */
virtual std::shared_ptr<Lock> getLock() const = 0;
/** @return the MountBehaviour of this device */
virtual MountBehaviour getMountBehaviour() const { return mountBehaviour; }
/** @return true if the SD card was mounted, returns false when it was not or when a timeout happened. */
bool isMounted(TickType_t timeout = kernel::MAX_TICKS) const { return getState(timeout) == State::Mounted; }
};
/** Return the SdCard device if the path is within the SdCard mounted path (path std::string::starts_with() check), otherwise return nullptr */
std::shared_ptr<SdCardDevice> find(const std::string& path);
/**
* Attempt to find an SD card that the specified belongs to,
* and returns its lock if the SD card is mounted. Otherwise it returns nullptr.
* @param[in] a path on a file system (e.g. file, directory, etc.)
* @return the lock of a mounted SD card or otherwise null
*/
std::shared_ptr<Lock> findSdCardLock(const std::string& path);
} // namespace tt::hal

View File

@ -0,0 +1,20 @@
#pragma once
#include <memory.h>
#include <string.h>
#include <Tactility/Lock.h>
namespace tt::hal::sdcard {
/**
* Attempt to find an SD card that the specified belongs to,
* and returns its lock if the SD card is mounted. Otherwise it returns nullptr.
* @param[in] a path on a file system (e.g. file, directory, etc.)
* @return the lock of a mounted SD card or otherwise null
*/
std::shared_ptr<Lock> findSdCardLock(const std::string& path);
void mountAll();
}

View File

@ -1,7 +0,0 @@
#pragma once
namespace tt::hal::sdcard {
void mountAll();
}

View File

@ -2,7 +2,6 @@
#include <Tactility/file/File.h>
#include <Tactility/file/FileLock.h>
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <Tactility/Logger.h>
#include <Tactility/LogMessages.h>
#include <Tactility/MountPoints.h>

View File

@ -1,7 +1,6 @@
#include "Tactility/app/fileselection/State.h"
#include <Tactility/file/File.h>
#include "Tactility/hal/sdcard/SdCardDevice.h"
#include <Tactility/Logger.h>
#include <Tactility/MountPoints.h>
#include <Tactility/kernel/Platform.h>

View File

@ -1,7 +1,6 @@
#include "Tactility/file/FileLock.h"
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <Tactility/Mutex.h>
#include <Tactility/hal/SdCard.h>
namespace tt::file {

View File

@ -5,7 +5,7 @@
#include <tactility/hal/Device.h>
#include <Tactility/hal/display/DisplayDevice.h>
#include <Tactility/hal/sdcard/SdCardMounting.h>
#include <Tactility/hal/SdCard.h>
#include <Tactility/hal/touch/TouchDevice.h>
#include <Tactility/kernel/SystemEvents.h>

View File

@ -1,12 +1,11 @@
#include "Tactility/hal/sdcard/SdCardDevice.h"
#include <Tactility/lvgl/LvglSync.h>
#include <tactility/device.h>
#include <tactility/drivers/sdcard.h>
#include <tactility/filesystem/file_system.h>
#include <cstring>
#include <string>
#include <memory>
namespace tt::hal::sdcard {
@ -38,4 +37,14 @@ std::shared_ptr<Lock> findSdCardLock(const std::string& path) {
return ctx.result;
}
void mountAll() {
device_for_each_of_type(&SDCARD_TYPE, nullptr, [](::Device* device, void*) -> bool {
if (!device_is_ready(device)) {
if (device_start(device) != ERROR_NONE) {
}
}
return true;
});
}
}

View File

@ -1,52 +0,0 @@
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <tactility/filesystem/file_system.h>
#include <cstring>
namespace tt::hal::sdcard {
static error_t mount(void* data) {
auto* device = static_cast<SdCardDevice*>(data);
auto path = device->getMountPath();
if (!device->mount(path)) return ERROR_UNDEFINED;
return ERROR_NONE;
}
static error_t unmount(void* data) {
auto* device = static_cast<SdCardDevice*>(data);
if (!device->unmount()) return ERROR_UNDEFINED;
return ERROR_NONE;
}
static bool is_mounted(void* data) {
auto* device = static_cast<SdCardDevice*>(data);
return device->isMounted();
}
static error_t get_path(void* data, char* out_path, size_t out_path_size) {
auto* device = static_cast<SdCardDevice*>(data);
const auto mount_path = device->getMountPath();
if (mount_path.size() >= out_path_size) return ERROR_BUFFER_OVERFLOW;
if (mount_path.empty()) return ERROR_INVALID_STATE;
strncpy(out_path, mount_path.c_str(), out_path_size);
return ERROR_NONE;
}
FileSystemApi sdCardDeviceApi = {
.mount = mount,
.unmount = unmount,
.is_mounted = is_mounted,
.get_path = get_path
};
SdCardDevice::SdCardDevice(MountBehaviour mountBehaviour) : mountBehaviour(mountBehaviour) {
fileSystem = file_system_add(&sdCardDeviceApi, this);
check(fileSystem != nullptr);
}
SdCardDevice::~SdCardDevice() {
file_system_remove(fileSystem);
}
}

View File

@ -1,36 +0,0 @@
#include <Tactility/hal/sdcard/SdCardMounting.h>
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <Tactility/Logger.h>
#include <format>
namespace tt::hal::sdcard {
static const auto LOGGER = Logger("SdCardMounting");
constexpr auto* TT_SDCARD_MOUNT_POINT = "/sdcard";
static void mount(const std::shared_ptr<SdCardDevice>& sdcard, const std::string& path) {
LOGGER.info("Mounting sdcard at {}", path);
if (!sdcard->mount(path)) {
LOGGER.warn("SD card mount failed for {} (init can continue)", path);
}
}
static std::string getMountPath(int index, int count) {
return (count == 1) ? TT_SDCARD_MOUNT_POINT : std::format("{}{}", TT_SDCARD_MOUNT_POINT, index);
}
void mountAll() {
const auto sdcards = hal::findDevices<SdCardDevice>(Device::Type::SdCard);
// Numbered mount path name
for (int i = 0; i < sdcards.size(); i++) {
auto sdcard = sdcards[i];
if (!sdcard->isMounted() && sdcard->getMountBehaviour() == SdCardDevice::MountBehaviour::AtBoot) {
std::string mount_path = getMountPath(i, sdcards.size());
mount(sdcard, mount_path);
}
}
}
}

View File

@ -16,7 +16,6 @@
#include <Tactility/app/AppRegistration.h>
#include <Tactility/app/AppManifest.h>
#include <Tactility/app/App.h>
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <Tactility/service/wifi/Wifi.h>
#include <esp_wifi_default.h>
#include <Tactility/network/HttpdReq.h>

View File

@ -8,7 +8,6 @@
#include <Tactility/Paths.h>
#include <Tactility/Tactility.h>
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <dirent.h>
#include <format>
#include <map>

View File

@ -1,7 +1,6 @@
#include <Tactility/MountPoints.h>
#include <Tactility/file/File.h>
#include <Tactility/file/PropertiesFile.h>
#include <Tactility/hal/sdcard/SdCardDevice.h>
#include <Tactility/Logger.h>
#include <Tactility/settings/BootSettings.h>

View File

@ -0,0 +1,14 @@
// SPDX-License-Identifier: Apache-2.0
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
#include <tactility/device.h>
extern const struct DeviceType SDCARD_TYPE;
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: Apache-2.0
#include <tactility/drivers/sdcard.h>
extern "C" {
const struct DeviceType SDCARD_TYPE {
.name = "sdcard"
};
}