Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
.pio/
.vscode/
*.pyc
crash_watch_*.txt
monitor_*.txt
postflash_*.txt
tcp_reply_*.txt
docs/flasher/firmware/
lib/tdeck_ui/Hardware/TDeck/SplashImage.h
3 changes: 2 additions & 1 deletion lib/lv_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
#define LV_DRAW_COMPLEX 1
#define LV_SHADOW_CACHE_SIZE 0
#define LV_CIRCLE_CACHE_SIZE 4
#define LV_IMG_CACHE_DEF_SIZE 0
#define LV_IMG_CACHE_DEF_SIZE 8
#define LV_GRADIENT_MAX_STOPS 2
#define LV_GRAD_CACHE_DEF_SIZE 0
#define LV_DITHER_GRADIENT 0
Expand Down Expand Up @@ -156,6 +156,7 @@
3RD PARTY LIBRARIES
*====================*/
#define LV_USE_QRCODE 1
#define LV_USE_PNG 1

/*====================
THEMES
Expand Down
139 changes: 139 additions & 0 deletions lib/tdeck_ui/Hardware/TDeck/LVGLFSDriver.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
// Copyright (c) 2024 microReticulum contributors
// SPDX-License-Identifier: MIT

#include "LVGLFSDriver.h"

#ifdef ARDUINO

#include "SDAccess.h"
#include <SD.h>
#include <Log.h>

namespace Hardware {
namespace TDeck {

// File handle wrapper — holds an open SD File object
struct FSFileHandle {
File file;
};

void LVGLFSDriver::init() {
if (!SDAccess::is_ready()) {
WARNING("LVGLFSDriver: SD card not ready, skipping init");
return;
}

static lv_fs_drv_t drv;
lv_fs_drv_init(&drv);

drv.letter = 'S';
drv.open_cb = fs_open;
drv.close_cb = fs_close;
drv.read_cb = fs_read;
drv.seek_cb = fs_seek;
drv.tell_cb = fs_tell;

lv_fs_drv_register(&drv);

INFO("LVGLFSDriver: Registered drive 'S' for SD card");
}

void* LVGLFSDriver::fs_open(lv_fs_drv_t* drv, const char* path, lv_fs_mode_t mode) {
(void)drv;

if (mode != LV_FS_MODE_RD) {
return NULL; // Read-only
}

// Build full SD path: prepend / prefix
// SD.open() already uses the /sd mount point internally
char full_path[128];
snprintf(full_path, sizeof(full_path), "/%s", path);

if (!SDAccess::acquire_bus(500)) {
return NULL;
}

FSFileHandle* handle = new FSFileHandle();
handle->file = SD.open(full_path, FILE_READ);

SDAccess::release_bus();

if (!handle->file) {
delete handle;
return NULL;
}

return handle;
}

lv_fs_res_t LVGLFSDriver::fs_close(lv_fs_drv_t* drv, void* file_p) {
(void)drv;
FSFileHandle* handle = (FSFileHandle*)file_p;

if (!SDAccess::acquire_bus(500)) {
// Still delete handle to avoid leak
delete handle;
return LV_FS_RES_HW_ERR;
}

handle->file.close();
SDAccess::release_bus();

delete handle;
return LV_FS_RES_OK;
}

lv_fs_res_t LVGLFSDriver::fs_read(lv_fs_drv_t* drv, void* file_p,
void* buf, uint32_t btr, uint32_t* br) {
(void)drv;
FSFileHandle* handle = (FSFileHandle*)file_p;

if (!SDAccess::acquire_bus(500)) {
*br = 0;
return LV_FS_RES_HW_ERR;
}

*br = handle->file.read((uint8_t*)buf, btr);

SDAccess::release_bus();
return LV_FS_RES_OK;
}

lv_fs_res_t LVGLFSDriver::fs_seek(lv_fs_drv_t* drv, void* file_p,
uint32_t pos, lv_fs_whence_t whence) {
(void)drv;
FSFileHandle* handle = (FSFileHandle*)file_p;

if (!SDAccess::acquire_bus(500)) {
return LV_FS_RES_HW_ERR;
}

SeekMode mode = SeekSet;
if (whence == LV_FS_SEEK_CUR) mode = SeekCur;
else if (whence == LV_FS_SEEK_END) mode = SeekEnd;

bool ok = handle->file.seek(pos, mode);

SDAccess::release_bus();
return ok ? LV_FS_RES_OK : LV_FS_RES_UNKNOWN;
}

lv_fs_res_t LVGLFSDriver::fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p) {
(void)drv;
FSFileHandle* handle = (FSFileHandle*)file_p;

if (!SDAccess::acquire_bus(500)) {
return LV_FS_RES_HW_ERR;
}

*pos_p = handle->file.position();

SDAccess::release_bus();
return LV_FS_RES_OK;
}

} // namespace TDeck
} // namespace Hardware

#endif // ARDUINO
42 changes: 42 additions & 0 deletions lib/tdeck_ui/Hardware/TDeck/LVGLFSDriver.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) 2024 microReticulum contributors
// SPDX-License-Identifier: MIT

#ifndef HARDWARE_TDECK_LVGLFSDRIVER_H
#define HARDWARE_TDECK_LVGLFSDRIVER_H

#ifdef ARDUINO

#include <lvgl.h>

namespace Hardware {
namespace TDeck {

/**
* LVGL filesystem driver for SD card access.
*
* Registers drive letter 'S' so LVGL can load files like:
* "S:tiles/14/8192/5455.png"
*
* Uses SDAccess mutex for SPI bus arbitration. The mutex is acquired
* per-read (not per-open) to avoid blocking display flushes during
* long tile decode operations.
*/
class LVGLFSDriver {
public:
static void init();

private:
static void* fs_open(lv_fs_drv_t* drv, const char* path, lv_fs_mode_t mode);
static lv_fs_res_t fs_close(lv_fs_drv_t* drv, void* file_p);
static lv_fs_res_t fs_read(lv_fs_drv_t* drv, void* file_p,
void* buf, uint32_t btr, uint32_t* br);
static lv_fs_res_t fs_seek(lv_fs_drv_t* drv, void* file_p,
uint32_t pos, lv_fs_whence_t whence);
static lv_fs_res_t fs_tell(lv_fs_drv_t* drv, void* file_p, uint32_t* pos_p);
};

} // namespace TDeck
} // namespace Hardware

#endif // ARDUINO
#endif // HARDWARE_TDECK_LVGLFSDRIVER_H
Loading
Loading