diff --git a/software/system/filesystem.c b/software/system/filesystem.c index fe6e3cc..c4a1a1f 100644 --- a/software/system/filesystem.c +++ b/software/system/filesystem.c @@ -5,6 +5,7 @@ #include "filesystem.h" #include "mini_qoi.h" +#include "serializers.h" #ifdef OST_USE_FF_LIBRARY #include "ff.h" @@ -27,6 +28,21 @@ static FIL File[2]; /* File object */ static DIR Dir; /* Directory object */ static FILINFO Finfo; +file_t file_open(const char *filename) +{ +#ifdef OST_USE_FF_LIBRARY + file_t fil; + FRESULT fr = f_open(&fil, filename, FA_READ); + if (fr != FR_OK) + { + debug_printf("ERROR: f_open %d\n\r", (int)fr); + } + return fil; +#else + return fopen(filename, "r"); +#endif +} + static FRESULT scan_files( char *path /* Pointer to the working buffer with start path */ ) @@ -82,20 +98,6 @@ void filesystem_mount() scan_files(""); } -// Ouvre le fichier d'index d'histoires -// Le format est le suivant : -// - Fichier texte, avec fin de ligne \n -// - Une ligne par histoire -// - la ligne contient le nom du répertoire au format UUIDv4 (36 caractères ASCII avec 4 tirets '-') - -// Exemple: d0ad13e4-06de-4e00-877c-d922fdd37d13 - -int is_multiple_of_37(int nombre) -{ - int plusGrandMultiple = (nombre / 37) * 37; - return (nombre - plusGrandMultiple) == 0; -} - /* // Loop in all directories void disk_start() @@ -138,30 +140,55 @@ void disk_start() } */ +static file_t IndexFile; + +static uint8_t IndexBuf[260]; + +static const char *IndexFileName = "index.ost"; + +#define TLV_ARRAY_TYPE 0xAB +#define TLV_OBJECT_TYPE 0xE7 +#define TLV_STRING_TYPE 0x3D + bool filesystem_read_index_file(ost_context_t *ctx) { FILINFO fno; - FRESULT fr = f_stat("index.ost", &fno); + FRESULT fr = f_stat(IndexFileName, &fno); ctx->number_of_stories = 0; ctx->current_story = 0; if (fr == FR_OK) { + + ctx->index_file_size = fno.fsize; + UINT br; + bool valid_file = false; - int size = fno.fsize; - // une ligne = 36 octets (UUID) + 1 octet (\n) = 37 - // Déjà, la taille doit être multiple de 37 - if (is_multiple_of_37(size) && (size > 0)) + + // Minimum size of TLV is type + length, so check if there is potential data + if (ctx->index_file_size > 3) { - valid_file = true; - ctx->number_of_stories = size / 37; - debug_printf("SUCCESS: found %d stories\r\n", ctx->number_of_stories); + FRESULT fr = f_open(&IndexFile, IndexFileName, FA_READ); + if (fr == FR_OK) + { + fr = f_read(&IndexFile, IndexBuf, 3, &br); + if (fr == FR_OK) + { + if ((br == 3) && (IndexBuf[0] = TLV_ARRAY_TYPE)) // Must be an array + { + // nomber of stories + ctx->number_of_stories = leu16_get(&IndexBuf[1]); + ctx->rd = 3; + debug_printf("SUCCESS: found %d stories\r\n", ctx->number_of_stories); + } + } + } + } + else + { + debug_printf("ERROR: index.ost not found\r\n"); } - } - else - { - debug_printf("ERROR: index.ost not found\r\n"); } } @@ -172,21 +199,6 @@ static uint8_t bmpImage[256]; static color_t line[320]; -file_t file_open(const char *filename) -{ -#ifdef OST_USE_FF_LIBRARY - file_t fil; - FRESULT fr = f_open(&fil, filename, FA_READ); - if (fr != FR_OK) - { - debug_printf("ERROR: f_open %d\n\r", (int)fr); - } - return fil; -#else - return fopen(filename, "r"); -#endif -} - void filesystem_display_image(const char *filename) { file_t fil; diff --git a/software/system/filesystem.h b/software/system/filesystem.h index 88ff402..bd246fb 100644 --- a/software/system/filesystem.h +++ b/software/system/filesystem.h @@ -2,12 +2,7 @@ #define FILESYSTEM_H #include - -typedef struct -{ - uint32_t number_of_stories; - uint32_t current_story; -} ost_context_t; +#include "system.h" bool filesystem_read_index_file(ost_context_t *ctx); void filesystem_mount(); diff --git a/software/system/fs_task.c b/software/system/fs_task.c index 77847f3..4814ffe 100644 --- a/software/system/fs_task.c +++ b/software/system/fs_task.c @@ -133,25 +133,25 @@ void FsTask(void *args) { switch (FsState) { - FS_PLAY_SOUND: + case FS_PLAY_SOUND: play_sound_file(fs_ev->filename); FsState = FS_WAIT_FOR_EVENT; break; - FS_DISPLAY_IMAGE: + case FS_DISPLAY_IMAGE: filesystem_display_image(fs_ev->filename); FsState = FS_WAIT_FOR_EVENT; break; - FS_LOAD_INDEX: + case FS_LOAD_INDEX: filesystem_read_index_file(&OstContext); FsState = FS_WAIT_FOR_EVENT; break; - FS_LOAD_STORY: + case FS_LOAD_STORY: filesystem_load_rom(fs_ev->mem, fs_ev->filename); // ROM loaded, execute story FsState = FS_WAIT_FOR_EVENT; break; - FS_WAIT_FOR_EVENT: + case FS_WAIT_FOR_EVENT: default: res = qor_mbox_wait(&FsMailBox, (void **)&fs_ev, 1000); if (res == QOR_MBOX_OK) diff --git a/software/system/fs_task.h b/software/system/fs_task.h index 8c6dc86..7da90c8 100644 --- a/software/system/fs_task.h +++ b/software/system/fs_task.h @@ -1,5 +1,7 @@ #ifndef FS_TASK_H #define FS_TASK_H +void fs_task_scan_index(); void fs_task_initialize(); + #endif // FS_TASK_H diff --git a/software/system/hmi_task.c b/software/system/hmi_task.c index 34953f0..9b855d7 100644 --- a/software/system/hmi_task.c +++ b/software/system/hmi_task.c @@ -31,6 +31,13 @@ typedef struct uint8_t ev; } ost_hmi_event_t; +typedef enum +{ + OST_SYS_WAIT_INDEX, + OST_SYS_PLAY_STORY_TITLE, + OST_SYS_WAIT_USER_EVENT +} ost_system_state_t; + // =========================================================================================================== // GLOBAL STORY VARIABLES // =========================================================================================================== @@ -44,6 +51,10 @@ static ost_hmi_event_t HmiEvent; static ost_hmi_event_t HmiQueue[10]; +static ost_system_state_t OstState = OST_SYS_WAIT_INDEX; + +static ost_context_t OstContext; + // =========================================================================================================== // HMI TASK (user interface, buttons manager, LCD) // =========================================================================================================== @@ -55,6 +66,7 @@ void HmiTask(void *args) // filesystem_display_image("/ba869e4b-03d6-4249-9202-85b4cec767a7/images/bird.qoi"); // Start by scanning the index file + fs_task_scan_index(); while (1) { @@ -62,6 +74,18 @@ void HmiTask(void *args) if (res == QOR_MBOX_OK) { + switch (OstState) + { + case OST_SYS_PLAY_STORY_TITLE: + break; + + case OST_SYS_WAIT_USER_EVENT: + break; + + case OST_SYS_WAIT_INDEX: + default: + break; + } } else { @@ -70,8 +94,19 @@ void HmiTask(void *args) } } +void hmi_task_ost_ready(uint32_t number_of_stories) +{ + static ost_hmi_event_t OsReadyEv = { + .ev = OST_SYS_PLAY_STORY_TITLE}; + + OstContext.number_of_stories = number_of_stories; + OstContext.current_story = 0; + qor_mbox_notify(&HmiMailBox, (void **)&OsReadyEv, QOR_MBOX_OPTION_SEND_BACK); +} + void hmi_task_initialize() { + OstState = OST_SYS_WAIT_INDEX; qor_mbox_init(&HmiMailBox, (void **)&HmiQueue, 10); qor_create_thread(&HmiTcb, HmiTask, HmiStack, sizeof(HmiStack) / sizeof(HmiStack[0]), HMI_TASK_PRIORITY, "HmiTask"); // less priority is the HMI (user inputs and LCD) diff --git a/software/system/hmi_task.h b/software/system/hmi_task.h index 3e8efdb..70ce9e5 100644 --- a/software/system/hmi_task.h +++ b/software/system/hmi_task.h @@ -1,6 +1,10 @@ #ifndef HMI_TASK_H #define HMI_TASK_H +#include + void hmi_task_initialize(); +void hmi_task_ost_ready(uint32_t number_of_stories); + #endif // HMI_TASK_H diff --git a/software/system/qor_armv6m.s b/software/system/qor_armv6m.s index 9865201..48df9b0 100644 --- a/software/system/qor_armv6m.s +++ b/software/system/qor_armv6m.s @@ -102,7 +102,7 @@ qor_switch_context: msr psp, r0 @ new task stack top address - str r0, [r1] @ Save the new top of stack + // str r0, [r1] @ Save the new top of stack subs r0, r0, #32 ldmia r0!, {r4-r7} diff --git a/software/system/sdcard.c b/software/system/sdcard.c index 9810504..636e6e5 100644 --- a/software/system/sdcard.c +++ b/software/system/sdcard.c @@ -304,7 +304,7 @@ static SD_Error SD_ReceiveData(uint8_t *data, uint16_t len) /* receive the rest of data... */ // for (i = 1; i < len; ++i) // data[i] = SD_SpiWriteByte(0xFF); - ost_hal_sdcard_spi_read(&data[1], len); + ost_hal_sdcard_spi_read(&data[1], (len - 1)); /* get CRC bytes (not really needed by us, but required by SD) */ SD_SpiWriteByte(0xFF); diff --git a/software/system/system.h b/software/system/system.h index 5987487..2cfa7d9 100644 --- a/software/system/system.h +++ b/software/system/system.h @@ -1,9 +1,20 @@ #ifndef SYSTEM_H #define SYSTEM_H +#include + // On regroupe ici au les priorités des différents threads afin d'avoir une vision plus large #define HMI_TASK_PRIORITY 1 #define VM_TASK_PRIORITY 2 #define FS_TASK_PRIORITY 3 ///< High priority for audio / file system access +typedef struct +{ + uint32_t number_of_stories; + uint32_t current_story; + uint32_t index_file_size; + uint32_t rd; ///!< Read index in the Index file + +} ost_context_t; + #endif // SYSTEM_H diff --git a/software/system/vm_task.c b/software/system/vm_task.c index 435c030..bbbd1b1 100644 --- a/software/system/vm_task.c +++ b/software/system/vm_task.c @@ -2,6 +2,7 @@ #include #include #include +#include #include "ost_hal.h" #include "debug.h" diff --git a/story-editor/src/resources_dock.cpp b/story-editor/src/resources_dock.cpp index 11d0a8f..20376eb 100644 --- a/story-editor/src/resources_dock.cpp +++ b/story-editor/src/resources_dock.cpp @@ -27,7 +27,12 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model) std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing); Resource res; - res.format = "BMP"; + + std::string ext = p.extension(); + ext.erase(ext.begin()); // remove '.' dot sign + std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper); + + res.format = ext; res.type = "image"; res.file = p.filename().generic_string(); m_resourcesModel.Append(res); @@ -38,7 +43,7 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model) QString fileName = QFileDialog::getOpenFileName(this, tr("Open File"), ".", - tr("Sound files (*.wav *.mp3 *.m4a)")); + tr("Sound files (*.wav *.mp3)")); if (std::filesystem::exists(fileName.toStdString())) { @@ -47,7 +52,12 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model) std::filesystem::copy(p, p2, std::filesystem::copy_options::overwrite_existing); Resource res; - res.format = "WAV"; + + std::string ext = p.extension(); + ext.erase(ext.begin()); // remove '.' dot sign + std::transform(ext.begin(), ext.end(), ext.begin(), ::toupper); + + res.format = ext; res.type = "sound"; res.file = p.filename().generic_string(); m_resourcesModel.Append(res); diff --git a/story-editor/src/story_project.cpp b/story-editor/src/story_project.cpp index a209d9f..a744e7b 100644 --- a/story-editor/src/story_project.cpp +++ b/story-editor/src/story_project.cpp @@ -12,18 +12,68 @@ void StoryProject::New(const std::string &uuid, const std::string &file_path) Initialize(file_path); } +#define TLV_ARRAY_TYPE 0xAB +#define TLV_OBJECT_TYPE 0xE7 +#define TLV_STRING_TYPE 0x3D + + +class Tlv +{ +public: + explicit Tlv(const std::string &filename) + { + m_file = std::ofstream(filename, std::ios::out | std::ios::binary); + } + + ~Tlv() { + m_file.close(); + } + + void add_array(uint16_t size) + { + m_file.write(reinterpret_cast(&m_objectType), sizeof(m_objectType)); + m_file.write(reinterpret_cast(&size), sizeof(size)); + } + + void add_string(const char *s, uint16_t size) + { + m_file.write(reinterpret_cast(&m_stringType), sizeof(m_stringType)); + m_file.write(reinterpret_cast(&size), sizeof(size)); + m_file.write(s, size); + } + + void add_object(uint16_t entries) + { + m_file.write(reinterpret_cast(&m_arrayType), sizeof(m_arrayType)); + m_file.write(reinterpret_cast(&entries), sizeof(entries)); + } + +private: + std::ofstream m_file; + + uint8_t m_arrayType = TLV_ARRAY_TYPE; + uint8_t m_objectType = TLV_OBJECT_TYPE; + uint8_t m_stringType = TLV_STRING_TYPE; + +}; + + + void StoryProject::SaveStory(const std::vector &m_program) { std::ofstream o(m_working_dir + std::filesystem::path::preferred_separator + "story.c32", std::ios::out | std::ios::binary); o.write(reinterpret_cast(m_program.data()), m_program.size()); o.close(); - // Generate title files - std::ofstream index(m_working_dir + std::filesystem::path::preferred_separator + "index.ost"); - index << "/" << m_uuid << "/images/" << m_titleImage << "\n"; - index << "/" << m_uuid << "/sounds/" << m_titleSound << "\n"; - index.close(); + Tlv tlv(m_working_dir + std::filesystem::path::preferred_separator + "index.ost"); + + tlv.add_array(1); + + tlv.add_object(3); + tlv.add_string(m_uuid.c_str(), m_uuid.size()); // uuid + tlv.add_string(m_titleImage.c_str(), m_titleImage.size()); // title image + tlv.add_string(m_titleSound.c_str(), m_titleSound.size()); // title sound } void StoryProject::Initialize(const std::string &file_path)