From 3a194bdb2ab765759978a40a6ec7865da1a7822b Mon Sep 17 00:00:00 2001 From: KoDer Date: Mon, 8 Jun 2026 23:39:25 +0700 Subject: [PATCH] vfs --- platformio.ini | 4 +- src/bin/shell/shell.cpp | 4 + src/bin/shell/shell.hpp | 3 +- src/boot/entry.cpp | 51 ++------ src/drivers/fs/fs.cpp | 52 ++++++++- src/drivers/fs/fs.hpp | 1 + src/drivers/fs/handlers.cpp | 224 +++++++++++++++++++++++++++++++++--- src/drivers/fs/handlers.hpp | 26 ++++- src/lib/runtime/PIC.cpp | 28 ----- src/lib/runtime/RT.hpp | 2 - src/lib/service/uart.hpp | 56 +++++++++ 11 files changed, 360 insertions(+), 91 deletions(-) create mode 100644 src/lib/service/uart.hpp diff --git a/platformio.ini b/platformio.ini index 74556ec..9dc65dd 100755 --- a/platformio.ini +++ b/platformio.ini @@ -4,4 +4,6 @@ board = esp32-s3-devkitc-1 framework = espidf monitor_speed = 115200 upload_speed = 921600 -board_build.partitions = partitions.csv \ No newline at end of file +board_build.partitions = partitions.csv + +monitor_filters = esp32_exception_decoder, colorize diff --git a/src/bin/shell/shell.cpp b/src/bin/shell/shell.cpp index e69de29..21fa949 100644 --- a/src/bin/shell/shell.cpp +++ b/src/bin/shell/shell.cpp @@ -0,0 +1,4 @@ +void shell_init() { + +} + diff --git a/src/bin/shell/shell.hpp b/src/bin/shell/shell.hpp index dcc830d..0921615 100644 --- a/src/bin/shell/shell.hpp +++ b/src/bin/shell/shell.hpp @@ -1,7 +1,6 @@ #ifndef SHELL_HPP #define SHELL_HPP - - +void shell_init(); #endif \ No newline at end of file diff --git a/src/boot/entry.cpp b/src/boot/entry.cpp index ed593b4..dc16241 100755 --- a/src/boot/entry.cpp +++ b/src/boot/entry.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -13,14 +14,15 @@ #include "boot/entry.hpp" #include "boot/answer_code.hpp" #include "lib/runtime/RT.hpp" +#include "lib/service/uart.hpp" extern Handler_vfs boot_handler; -void log_result(int res, char *service_name){ +void log_result(int res,char *service_name){ if (res == OS_OK) { printf("[ \033[0;32mOK\033[0m ] %s\n", service_name); } else { - char *err_text = "Error"; + const char *err_text = "Error"; const char *msg = get_error(res); if (strncmp(msg, err_text, 5) == 0) { printf("[ \033[0;31mEROR\033[0m ] %s initialization: %s (%d)\n", service_name, msg, res); @@ -31,55 +33,20 @@ void log_result(int res, char *service_name){ } Result test_fn(descriptor *fn) { - /*printf("Вызов функции %s\n", fn->name); - fn->ret.int_v = 42;*/ + printf("Вызов функции %s\n", fn->name); + fn->ret.int_v = 42; return {OS_OK, *fn}; } int main_entry() { - printf("Free IRAM: %d bytes\n", heap_caps_get_free_size(MALLOC_CAP_INTERNAL | MALLOC_CAP_32BIT | MALLOC_CAP_EXEC)); - printf("Largest IRAM block: %d bytes\n", heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_32BIT | MALLOC_CAP_EXEC)); - - //printf("\033[2J\033[H"); printf("OS started\n"); log_result(init_fs(), "VFS"); + log_result(mount(MOUNT_HANDLER, boot_handler.path, boot_handler.path, &boot_handler), "MOUNT_BOOT"); + log_result(regist_uart(), "UART"); - mount(MOUNT_HANDLER, boot_handler.path, boot_handler.path, &boot_handler); + list_files_recursive("/"); - /* - - boot_handler.link_function("/test_fn", test_fn); - - int fd = open("/boot/test_fn", O_RDWR | O_CREAT | O_TRUNC); - if (fd >= 0) { - //write(fd, "Hello, world!", 13); - - Result res_buffer; - ssize_t bytes_read = read(fd, &res_buffer, sizeof(Result)); - - if (bytes_read == sizeof(Result)) { - printf("Структура успешно получена напрямую из ядра! [%d]\n", res_buffer.data.ret.int_v); - } - - close(fd); - } - - */ - - printf("Free IRAM: %u bytes\n", - heap_caps_get_free_size(MALLOC_CAP_EXEC)); - - printf("Largest IRAM block: %u bytes\n", - heap_caps_get_largest_free_block(MALLOC_CAP_EXEC)); - - run_app_from_iram(); - - while (true) - { - vTaskDelay(1000 / portTICK_PERIOD_MS); - } - return 0; } diff --git a/src/drivers/fs/fs.cpp b/src/drivers/fs/fs.cpp index c6634df..8aea94b 100755 --- a/src/drivers/fs/fs.cpp +++ b/src/drivers/fs/fs.cpp @@ -5,6 +5,7 @@ #include #include + #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "esp_spiffs.h" @@ -75,7 +76,6 @@ void create_fs() { printf("user_password_sha256: %s\n", user_password_sha256); int total_prograss = 0; - int max_prograss = 15; mkdir("/bin", 0777); total_prograss++; mkdir("/boot", 0777); total_prograss++; @@ -107,6 +107,42 @@ void create_fs() { } +void list_files_recursive(const char *path) { + DIR *dir = opendir(path); + if (dir == NULL) return; + + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + const char *type = (entry->d_type == DT_DIR) ? " DIR" : "FILE"; + + // ИСПРАВЛЕНИЕ: Красивый вывод без // + if (strcmp(path, "/") == 0) { + printf("[%s] /%s\n", type, entry->d_name); + } else { + printf("[%s] %s/%s\n", type, path, entry->d_name); + } + + if (entry->d_type == DT_DIR) { + char next_path[300]; + + // ИСПРАВЛЕНИЕ: Безопасное склеивание корня + if (strcmp(path, "/") == 0) { + snprintf(next_path, sizeof(next_path), "/%s", entry->d_name); + } else { + snprintf(next_path, sizeof(next_path), "%s/%s", path, entry->d_name); + } + + list_files_recursive(next_path); + } + } + closedir(dir); +} + + void list_files(const char *path) { printf("Чтение директории: %s\n", path); @@ -187,10 +223,24 @@ uint32_t mount(fs_type_t type, const char *path, const char *label, const Handle esp_vfs_t conf = {}; memset(&conf, 0, sizeof(conf)); conf.flags = ESP_VFS_FLAG_CONTEXT_PTR; + + // Основные операции с файлами conf.open_p = &Handler_vfs::open_vfs; conf.read_p = &Handler_vfs::read_vfs; conf.write_p = &Handler_vfs::write_vfs; conf.close_p = &Handler_vfs::close_vfs; + + // Операции с директориями + conf.opendir_p = &Handler_vfs::opendir_vfs; + conf.readdir_p = &Handler_vfs::readdir_vfs; + conf.closedir_p = &Handler_vfs::closedir_vfs; + + // Получение информации о файлах/директориях + conf.stat_p = &Handler_vfs::stat_vfs; + + // Переименование + conf.rename_p = &Handler_vfs::rename_vfs; + switch (esp_vfs_register(path, &conf, (void*)class_fs)) { case ESP_OK: return OS_OK; diff --git a/src/drivers/fs/fs.hpp b/src/drivers/fs/fs.hpp index 8be570f..d2a90b0 100755 --- a/src/drivers/fs/fs.hpp +++ b/src/drivers/fs/fs.hpp @@ -21,6 +21,7 @@ typedef enum { int init_fs(); void list_files(const char *path); +void list_files_recursive(const char *path); bool file_exists(const char *path); uint32_t mount(fs_type_t type, const char *path, const char *label, const Handler_vfs *class_fs = NULL); int unmount(); diff --git a/src/drivers/fs/handlers.cpp b/src/drivers/fs/handlers.cpp index 2b3ad83..ab010d7 100644 --- a/src/drivers/fs/handlers.cpp +++ b/src/drivers/fs/handlers.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "boot/answer_code.hpp" #include "drivers/fs/handlers.hpp" @@ -7,6 +8,80 @@ Handler_vfs boot_handler("/boot"); +void parse_and_fill_arg_c(const char* start, size_t len, arg* out_arg) { + if (len == 0) { + out_arg->type = argNONE_t; + return; + } + size_t copy_len = (len > 31) ? 31 : len; + char tmp[33]; + memcpy(tmp, start, copy_len); + tmp[copy_len] = '\0'; + + char* endptr; + + long int_val = strtol(tmp, &endptr, 10); + if (*endptr == '\0') { + out_arg->type = argINT_t; + out_arg->value.valueINT = (int)int_val; + return; + } + + float float_val = strtof(tmp, &endptr); + if (*endptr == '\0') { + out_arg->type = argFLOAT_t; + out_arg->value.valueFLOAT = float_val; + return; + } + + out_arg->type = argSTRING_t; + memcpy(out_arg->value.valueSTRING, tmp, copy_len + 1); +} + +void parse_args_c_style(const char* input, arg* args_array) { + for (int i = 0; i < 8; i++) { + args_array[i].type = argNONE_t; + } + + if (input == nullptr) return; + + const char* token_start = input; + + if (input[0] == '\\' && input[1] == '$') { + input += 2; + token_start = input; + } + + int arg_index = 0; + + while (*input != '\0') { + if (*input == '\\' && *(input + 1) == '$') { + if (input != token_start && *(input - 1) == '\\') { + input += 2; + continue; + } + + size_t token_len = input - token_start; + + if (arg_index < 8) { + parse_and_fill_arg_c(token_start, token_len, &args_array[arg_index]); + arg_index++; + } + + input += 2; + token_start = input; + continue; + } + + input++; + } + + size_t last_len = input - token_start; + if (last_len > 0 && arg_index < 8) { + parse_and_fill_arg_c(token_start, last_len, &args_array[arg_index]); + } +} + Handler_vfs::Handler_vfs(const char *path) { strcpy(this->path, path); count_fn = 0; @@ -18,9 +93,8 @@ Handler_vfs::Handler_vfs(const char *path) { }; Handler_vfs::~Handler_vfs() { - if (functions != nullptr) { - free(functions); - } + if (functions != nullptr) free(functions); + if (descriptors != nullptr) free(descriptors); } int Handler_vfs::link_function(const char *name, func_t func) { @@ -29,7 +103,6 @@ int Handler_vfs::link_function(const char *name, func_t func) { size_t new_size = new_capacity * sizeof(function_file); function_file* temp = (function_file*)realloc(functions, new_size); - if (temp != nullptr) { functions = temp; capacity_fn = new_capacity; @@ -38,13 +111,14 @@ int Handler_vfs::link_function(const char *name, func_t func) { } } - strncpy(functions[count_fn].name, name, 32); + strncpy(functions[count_fn].name, name, 31); + functions[count_fn].name[31] = '\0'; functions[count_fn].handler = func; - count_fn++; return 0; } + int Handler_vfs::unlink_function(const char *name) { int index = -1; for (int i = 0; i < count_fn; i++) { @@ -59,7 +133,6 @@ int Handler_vfs::unlink_function(const char *name) { for (int i = index; i < count_fn - 1; i++) { functions[i] = functions[i + 1]; } - count_fn--; if (capacity_fn - count_fn >= 15 && capacity_fn > 10) { @@ -79,7 +152,10 @@ int Handler_vfs::unlink_function(const char *name) { int Handler_vfs::open(const char *name, int flags, int mode) { int fn_idx = -1; for (int i = 0; i < count_fn; i++) { - if (strcmp(functions[i].name, name) == 0) { { fn_idx = i; break; } } + if (strcmp(functions[i].name, name) == 0) { + fn_idx = i; + break; + } } if (fn_idx == -1) return OS_ERR_NOT_FOUND; @@ -106,23 +182,27 @@ int Handler_vfs::open(const char *name, int flags, int mode) { memset(descriptors[target_fd].name, 0, 32); strncpy(descriptors[target_fd].name, name, 31); descriptors[target_fd].handler = functions[fn_idx].handler; + + for(int i=0; i<8; ++i) descriptors[target_fd].args[i].type = argNONE_t; return target_fd; } + int Handler_vfs::open_vfs(void* ctx, const char *path, int flags, int mode) { Handler_vfs* self = (Handler_vfs*)ctx; return self->open(path, flags, mode); } ssize_t Handler_vfs::read(int fd, void *dst, size_t size) { - if (fd < 0 || fd >= count_ds || descriptors[fd].handler == nullptr) return OS_ERR_NOT_FOUND; - if (dst == nullptr) return OS_ERR_NOT_FOUND; + if (dst == nullptr) { + descriptors[fd].handler(&descriptors[fd]); + return 0; + } if (size < sizeof(Result)) return OS_ERR_NO_MEMORY; Result res = descriptors[fd].handler(&descriptors[fd]); - memcpy(dst, &res, sizeof(res)); return sizeof(res); @@ -134,9 +214,22 @@ ssize_t Handler_vfs::read_vfs(void* ctx, int fd, void *dst, size_t size) { } ssize_t Handler_vfs::write(int fd, const void *src, size_t size) { - //printf("Handler write [%d]\n", fd); - return 0; + if (fd < 0 || fd >= count_ds || descriptors[fd].handler == nullptr) { + return OS_ERR_NOT_FOUND; + } + if (src == nullptr || size == 0) { + return OS_ERR_INVALID_ARG; + } + char tmp_input[128]; + size_t copy_size = (size > 127) ? 127 : size; + + memcpy(tmp_input, src, copy_size); + tmp_input[copy_size] = '\0'; + parse_args_c_style(tmp_input, descriptors[fd].args); + + return (ssize_t)size; } + ssize_t Handler_vfs::write_vfs(void* ctx, int fd, const void *src, size_t size) { Handler_vfs* self = (Handler_vfs*)ctx; return self->write(fd, src, size); @@ -147,16 +240,119 @@ int Handler_vfs::close(int fd) { descriptors[fd].handler = nullptr; return 0; } + int Handler_vfs::close_vfs(void* ctx, int fd) { Handler_vfs* self = (Handler_vfs*)ctx; return self->close(fd); } int Handler_vfs::rename(const char *src, const char *dst) { - printf("Handler rename [%s] [%s]\n", src, dst); + int fn_idx = -1; + for (int i = 0; i < count_fn; i++) { + if (strcmp(functions[i].name, src) == 0) { + fn_idx = i; + break; + } + } + if (fn_idx == -1) return OS_ERR_NOT_FOUND; + + strncpy(functions[fn_idx].name, dst, 31); + functions[fn_idx].name[31] = '\0'; return 0; } + int Handler_vfs::rename_vfs(void* ctx, const char *src, const char *dst) { Handler_vfs* self = (Handler_vfs*)ctx; return self->rename(src, dst); +} + +// --- РЕАЛИЗАЦИЯ РАБОТЫ С ДИРЕКТОРИЯМИ И STAT --- + +DIR* Handler_vfs::opendir(const char* name) { + // Выделяем память для состояния директории + descriptor_dir* dd = new descriptor_dir(); + strncpy(dd->path, name, 127); + dd->path[127] = '\0'; + dd->current_index = 0; + dd->handler = this; + + // Cast в DIR*, так как для VFS это просто непрозрачный указатель + return (DIR*)dd; +} + +DIR* Handler_vfs::opendir_vfs(void* ctx, const char* name) { + Handler_vfs* self = (Handler_vfs*)ctx; + return self->opendir(name); +} + +struct dirent* Handler_vfs::readdir(DIR* pdir) { + if (!pdir) return nullptr; + + descriptor_dir* dd = (descriptor_dir*)pdir; + Handler_vfs* self = dd->handler; + + if (dd->current_index >= self->count_fn) { + return nullptr; + } + + static struct dirent entry; + memset(&entry, 0, sizeof(entry)); + + const char* fn_name = self->functions[dd->current_index].name; + + if (fn_name[0] == '/') { + fn_name++; + } + + strncpy(entry.d_name, fn_name, sizeof(entry.d_name) - 1); + entry.d_name[sizeof(entry.d_name) - 1] = '\0'; + + dd->current_index++; + + return &entry; +} + + +struct dirent* Handler_vfs::readdir_vfs(void* ctx, DIR* pdir) { + Handler_vfs* self = (Handler_vfs*)ctx; + return self->readdir(pdir); +} + +int Handler_vfs::closedir(DIR* pdir) { + if (!pdir) return -1; + descriptor_dir* dd = (descriptor_dir*)pdir; + delete dd; // Освобождаем память, выделенную в opendir + return 0; +} + +int Handler_vfs::closedir_vfs(void* ctx, DIR* pdir) { + Handler_vfs* self = (Handler_vfs*)ctx; + return self->closedir(pdir); +} + +int Handler_vfs::stat(const char * path, struct stat * st) { + if (!st) return -1; + memset(st, 0, sizeof(struct stat)); + + // Ищем, является ли путь именем зарегистрированной функции (файлом) + for (int i = 0; i < count_fn; i++) { + if (strcmp(functions[i].name, path) == 0) { + st->st_mode = S_IFREG | 0666; // Обычный файл + st->st_size = sizeof(Result); + return 0; + } + } + + // Проверяем, является ли путь самой директорией (точкой монтирования) + if (strcmp(path, this->path) == 0 || strcmp(path, "/") == 0) { + st->st_mode = S_IFDIR | 0777; // Директория + return 0; + } + + return -1; // Не найдено +} + +int Handler_vfs::stat_vfs(void* ctx, const char * path, struct stat * st) { + Handler_vfs* self = (Handler_vfs*)ctx; + return self->stat(path, st); } \ No newline at end of file diff --git a/src/drivers/fs/handlers.hpp b/src/drivers/fs/handlers.hpp index 60c379a..f488318 100644 --- a/src/drivers/fs/handlers.hpp +++ b/src/drivers/fs/handlers.hpp @@ -4,13 +4,15 @@ #include #include #include +#include struct descriptor; struct Result; +class Handler_vfs; // Предварительное объявление typedef Result (*func_t)(descriptor*); -enum arg_t { argINT_t, argFLOAT_t, argSTRING_t }; +enum arg_t { argINT_t, argFLOAT_t, argSTRING_t, argNONE_t }; struct arg { arg_t type; @@ -33,6 +35,14 @@ struct descriptor func_t handler; }; +// Обновленная структура для хранения состояния открытой директории +struct descriptor_dir +{ + char path[128]; + int current_index; + Handler_vfs* handler; +}; + struct function_file { char name[32]; func_t handler; @@ -50,6 +60,7 @@ class Handler_vfs { Handler_vfs(const char *path); ~Handler_vfs(); + int link_function(const char *name, func_t func); int unlink_function(const char *name); @@ -68,9 +79,22 @@ class Handler_vfs { int rename(const char *src, const char *dst); static int rename_vfs(void* ctx, const char *src, const char *dst); + DIR* opendir(const char* name); + static DIR* opendir_vfs(void* ctx, const char* name); + + struct dirent* readdir(DIR* pdir); + static struct dirent* readdir_vfs(void* ctx, DIR* pdir); + + int closedir(DIR* pdir); + static int closedir_vfs(void* ctx, DIR* pdir); + + int stat(const char * path, struct stat * st); + static int stat_vfs(void* ctx, const char * path, struct stat * st); + private: function_file* functions; descriptor* descriptors; + descriptor_dir* descriptors_dirs; int count_fn = 0; int count_ds = 0; int capacity_fn = 0; diff --git a/src/lib/runtime/PIC.cpp b/src/lib/runtime/PIC.cpp index 4717f1e..e69de29 100644 --- a/src/lib/runtime/PIC.cpp +++ b/src/lib/runtime/PIC.cpp @@ -1,28 +0,0 @@ -#include -#include -#include "esp_heap_caps.h" -#include "esp_cpu.h" - -typedef int (*func_t)(void); - -void run_app_from_iram(void) -{ - uint8_t code[] = { - 0x36, 0x41, 0x00, 0x2c, 0xa2, 0x1d, 0xf0 - }; - - void *exec = heap_caps_malloc(sizeof(code), - MALLOC_CAP_EXEC | MALLOC_CAP_8BIT); - - memcpy(exec, code, sizeof(code)); - - //esp_cpu_invalidate_icache_all(); - - func_t f = (func_t)exec; - - int result = f(); - - printf("Result = %d\n", result); // Должно быть 42 - - heap_caps_free(exec); -} \ No newline at end of file diff --git a/src/lib/runtime/RT.hpp b/src/lib/runtime/RT.hpp index b6b782f..5a76dab 100644 --- a/src/lib/runtime/RT.hpp +++ b/src/lib/runtime/RT.hpp @@ -1,6 +1,4 @@ #ifndef RT_HPP #define RT_HPP -void run_app_from_iram(); - #endif \ No newline at end of file diff --git a/src/lib/service/uart.hpp b/src/lib/service/uart.hpp new file mode 100644 index 0000000..2b6649d --- /dev/null +++ b/src/lib/service/uart.hpp @@ -0,0 +1,56 @@ +#ifndef UART_HPP +#define UART_HPP + +#include "drivers/fs/handlers.hpp" +#include "boot/answer_code.hpp" + +extern Handler_vfs boot_handler; + +Result uart_read(descriptor *fn) { + int c = getchar(); + fn->ret.int_v = c; + return {OS_OK, *fn}; + +} +Result uart_write(descriptor *fn) { + for (int i = 0; i < 8; i++) { + if (fn->args[i].type == argNONE_t) { + break; + } + switch (fn->args[i].type) { + case argINT_t: + printf("%d",fn->args[i].value.valueINT); + break; + case argFLOAT_t: + printf("%f",fn->args[i].value.valueFLOAT); + break; + case argSTRING_t: + printf("%s", fn->args[i].value.valueSTRING); + break; + default: + break; + } + } + return {OS_OK, *fn}; +} + +uint32_t regist_uart() { + uint32_t err; + err = boot_handler.link_function("/uart/read", uart_read); + printf("\tmount uart_read: "); + if (err != OS_OK) { + return err; + printf("err(%s)\n", get_error(err)); + } + printf("ok\n"); + err = boot_handler.link_function("/uart/write", uart_write); + printf("\tmount uart_write: "); + if (err != OS_OK) { + return err; + printf("err(%s)\n", get_error(err)); + } + printf("ok\n"); + return OS_OK; +} + +#endif \ No newline at end of file