#ifndef SD_FILE_BROWSER_H #define SD_FILE_BROWSER_H #include /* Ограничения одинаковы для portable core, Modbus mailbox и GUI. */ #define SD_FILE_BROWSER_MAX_PATH 96U #define SD_FILE_BROWSER_MAX_NAME 48U #define SD_FILE_BROWSER_MAX_PAGE_ITEMS 3U #define SD_FILE_BROWSER_MAX_CHUNK_BYTES 64U typedef enum { /* Успех означает полностью сформированную страницу, а не только open. */ SD_FILE_BROWSER_OK = 0, /* BUSY оставляет retry политике приложения и ничего не пишет на носитель. */ SD_FILE_BROWSER_BUSY, SD_FILE_BROWSER_NOT_READY, SD_FILE_BROWSER_IO_ERROR, SD_FILE_BROWSER_INVALID_PATH, SD_FILE_BROWSER_INVALID_CURSOR, SD_FILE_BROWSER_NAME_TOO_LONG, SD_FILE_BROWSER_FILE_CHANGED, SD_FILE_BROWSER_NOT_LOG_FILE } SdFileBrowserStatus; typedef struct { /* Имя всегда завершается нулём и не содержит родительского пути. */ char name[SD_FILE_BROWSER_MAX_NAME + 1U]; uint32_t size; uint16_t modified_date; uint16_t modified_time; uint8_t is_directory; } SdFileBrowserEntry; typedef struct { /* Ответ имеет фиксированную RAM-ёмкость и никогда не выделяет heap. */ SdFileBrowserEntry items[SD_FILE_BROWSER_MAX_PAGE_ITEMS]; uint16_t next_offset; uint8_t count; uint8_t has_more; } SdFileBrowserPage; typedef struct { /* Metadata повторяется в каждом chunk и защищает bridge от склейки разных версий файла. */ uint32_t total_size; uint32_t offset; uint16_t modified_date; uint16_t modified_time; uint8_t length; uint8_t end_of_file; uint8_t data[SD_FILE_BROWSER_MAX_CHUNK_BYTES]; } SdFileBrowserChunk; typedef SdFileBrowserStatus (*SdFileBrowserListPageFn)( void *context, const char *path, uint16_t offset, uint8_t limit, SdFileBrowserPage *page); typedef struct { /* Context принадлежит платформе; portable core его не освобождает. */ void *context; SdFileBrowserListPageFn list_page; } SdFileBrowser; /* Принимается только логический путь от корня карты: "/" или "/dir/file". * Проверка не исправляет вход: неканонические строки отклоняются fail-closed. */ SdFileBrowserStatus SdFileBrowser_ValidatePath(const char *path); /* Разрешает только legacy TEMPLOG.MD или суточный temperature_*.md внутри * штатного корня niceOne/mounth; служебные JSON/прошивки сюда не попадают. */ SdFileBrowserStatus SdFileBrowser_ValidateLogFilePath(const char *path); /* Разрешает только сырой образ .bin/.fw внутри каталога niceOne/firmware. * Каталог отделён от журналов, чтобы прошивка и логи не смешивались. */ SdFileBrowserStatus SdFileBrowser_ValidateFirmwarePath(const char *path); /* Вызов делегирует порту ровно одну ограниченную страницу каталога. * Output предварительно очищается, поэтому ошибка не публикует старые имена. */ SdFileBrowserStatus SdFileBrowser_ListPage( const SdFileBrowser *browser, const char *path, uint16_t offset, uint8_t limit, SdFileBrowserPage *page); #endif /* SD_FILE_BROWSER_H */