mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-06 17:09:06 +01:00
firmware: put tasks into dedicated files with clean API, prepare story title image and sounds
This commit is contained in:
parent
cebd349af4
commit
084af988cb
21 changed files with 744 additions and 329 deletions
Binary file not shown.
BIN
art/pack/dragon.png
Normal file
BIN
art/pack/dragon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 106 KiB |
|
|
@ -33,12 +33,14 @@ set(OST_SRCS
|
||||||
system/sdcard.c
|
system/sdcard.c
|
||||||
system/ff_diskio_sdcard.c
|
system/ff_diskio_sdcard.c
|
||||||
system/debug.c
|
system/debug.c
|
||||||
system/picture.c
|
|
||||||
system/filesystem.c
|
system/filesystem.c
|
||||||
system/sdcard.c
|
system/sdcard.c
|
||||||
system/qor.c
|
system/qor.c
|
||||||
system/qor_armv6m.s
|
system/qor_armv6m.s
|
||||||
system/audio_player.c
|
system/audio_player.c
|
||||||
|
system/vm_task.c
|
||||||
|
system/hmi_task.c
|
||||||
|
system/fs_task.c
|
||||||
system/ff/ff.c
|
system/ff/ff.c
|
||||||
system/ff/ffsystem.c
|
system/ff/ffsystem.c
|
||||||
system/ff/ff_stubs.c
|
system/ff/ff_stubs.c
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,19 @@
|
||||||
#include "ost_hal.h"
|
#include "ost_hal.h"
|
||||||
|
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
|
#include "mini_qoi.h"
|
||||||
|
|
||||||
|
#ifdef OST_USE_FF_LIBRARY
|
||||||
|
#include "ff.h"
|
||||||
|
#include "diskio.h"
|
||||||
|
typedef FIL file_t;
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Use standard library
|
||||||
|
typedef FILE *file_t;
|
||||||
|
typedef int FRESULT;
|
||||||
|
#define F_OK
|
||||||
|
#endif
|
||||||
|
|
||||||
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
|
// SD_FAT_TYPE = 0 for SdFat/File as defined in SdFatConfig.h,
|
||||||
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
|
// 1 for FAT16/FAT32, 2 for exFAT, 3 for FAT16/FAT32 and exFAT.
|
||||||
|
|
@ -151,3 +164,130 @@ bool filesystem_read_index_file(ost_context_t *ctx)
|
||||||
debug_printf("ERROR: index.ost not found\r\n");
|
debug_printf("ERROR: index.ost not found\r\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mqoi_dec_t dec;
|
||||||
|
static mqoi_desc_t desc;
|
||||||
|
|
||||||
|
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;
|
||||||
|
unsigned int br;
|
||||||
|
|
||||||
|
fil = file_open(filename);
|
||||||
|
uint32_t imgW, imgH;
|
||||||
|
|
||||||
|
mqoi_desc_init(&desc);
|
||||||
|
|
||||||
|
// 1. Read header
|
||||||
|
f_read(&fil, &desc.magic[0], sizeof(mqoi_desc_t) - 1, &br);
|
||||||
|
|
||||||
|
uint8_t errn = mqoi_desc_verify(&desc, &imgW, &imgH);
|
||||||
|
|
||||||
|
if (errn)
|
||||||
|
{
|
||||||
|
debug_printf("Invalid image, code %d\n", errn);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_printf("Image dimensions: %d, %d\n", imgW, imgH);
|
||||||
|
|
||||||
|
uint32_t start, end, pxCount = 0;
|
||||||
|
|
||||||
|
volatile mqoi_rgba_t *px;
|
||||||
|
|
||||||
|
mqoi_dec_init(&dec, imgW * imgH);
|
||||||
|
|
||||||
|
// Serial.println("starting decode...");
|
||||||
|
int index = 256; // force refill first time
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
while (!mqoi_dec_done(&dec))
|
||||||
|
{
|
||||||
|
if (index >= sizeof(bmpImage))
|
||||||
|
{
|
||||||
|
// refill buffer
|
||||||
|
f_read(&fil, bmpImage, sizeof(bmpImage), &br);
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mqoi_dec_push(&dec, bmpImage[index++]);
|
||||||
|
|
||||||
|
while ((px = mqoi_dec_pop(&dec)) != NULL)
|
||||||
|
{
|
||||||
|
pxCount++;
|
||||||
|
|
||||||
|
line[x].r = px->r;
|
||||||
|
line[x].g = px->g;
|
||||||
|
line[x].b = px->b;
|
||||||
|
|
||||||
|
x++;
|
||||||
|
if (x >= 320)
|
||||||
|
{
|
||||||
|
ost_display_draw_h_line_rgb888(y, line);
|
||||||
|
x = 0;
|
||||||
|
y++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
f_close(&fil);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FS_MAX_SIZE_READ 256
|
||||||
|
|
||||||
|
void filesystem_load_rom(uint8_t *mem, const char *filename)
|
||||||
|
{
|
||||||
|
file_t fil;
|
||||||
|
FILINFO fno;
|
||||||
|
unsigned int br;
|
||||||
|
|
||||||
|
FRESULT fr = f_stat(filename, &fno);
|
||||||
|
|
||||||
|
if (fr == FR_OK)
|
||||||
|
{
|
||||||
|
int total_size = fno.fsize;
|
||||||
|
fil = file_open(filename);
|
||||||
|
int copied_size = 0;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
int read_size = total_size > FS_MAX_SIZE_READ ? FS_MAX_SIZE_READ : total_size;
|
||||||
|
|
||||||
|
f_read(&fil, &mem[copied_size], read_size, &br);
|
||||||
|
|
||||||
|
if (br == read_size)
|
||||||
|
{
|
||||||
|
total_size -= read_size;
|
||||||
|
copied_size += read_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug_printf("Read file error\n");
|
||||||
|
total_size = 0; // force exit
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (total_size > 0);
|
||||||
|
|
||||||
|
f_close(&fil);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,5 +11,7 @@ typedef struct
|
||||||
|
|
||||||
bool filesystem_read_index_file(ost_context_t *ctx);
|
bool filesystem_read_index_file(ost_context_t *ctx);
|
||||||
void filesystem_mount();
|
void filesystem_mount();
|
||||||
|
void filesystem_display_image(const char *filename);
|
||||||
|
void filesystem_load_rom(uint8_t *mem, const char *filename);
|
||||||
|
|
||||||
#endif // FILESYSTEM_H
|
#endif // FILESYSTEM_H
|
||||||
|
|
|
||||||
192
software/system/fs_task.c
Normal file
192
software/system/fs_task.c
Normal file
|
|
@ -0,0 +1,192 @@
|
||||||
|
/**
|
||||||
|
* @file fs_task.c
|
||||||
|
*
|
||||||
|
* @author your name (you@domain.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-07-29
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ost_hal.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "qor.h"
|
||||||
|
#include "audio_player.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "vm_task.h"
|
||||||
|
#include "fs_task.h"
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// DEFINITIONS
|
||||||
|
// ===========================================================================================================
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t ev;
|
||||||
|
} ost_audio_event_t;
|
||||||
|
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
FS_WAIT_FOR_EVENT,
|
||||||
|
FS_PLAY_SOUND,
|
||||||
|
FS_DISPLAY_IMAGE,
|
||||||
|
FS_LOAD_INDEX,
|
||||||
|
FS_LOAD_STORY
|
||||||
|
} fs_state_t;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
fs_state_t ev;
|
||||||
|
uint8_t *mem;
|
||||||
|
char *filename;
|
||||||
|
} ost_fs_event_t;
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// PRIVATE GLOBAL VARIABLES
|
||||||
|
// ===========================================================================================================
|
||||||
|
static qor_tcb_t FsTcb;
|
||||||
|
static uint32_t FsStack[4096];
|
||||||
|
|
||||||
|
static qor_mbox_t AudioMailBox;
|
||||||
|
|
||||||
|
static ost_audio_event_t wake_up;
|
||||||
|
|
||||||
|
static ost_audio_event_t AudioQueue[10];
|
||||||
|
|
||||||
|
static int dbg_state = 0;
|
||||||
|
|
||||||
|
static fs_state_t FsState = FS_WAIT_FOR_EVENT;
|
||||||
|
|
||||||
|
static qor_mbox_t FsMailBox;
|
||||||
|
|
||||||
|
static ost_fs_event_t FsEventQueue[10];
|
||||||
|
|
||||||
|
static ost_context_t OstContext;
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// FILE SYSTEM TASK
|
||||||
|
// ===========================================================================================================
|
||||||
|
|
||||||
|
// End of DMA transfer callback
|
||||||
|
static void audio_callback(void)
|
||||||
|
{
|
||||||
|
dbg_state = 1 - dbg_state;
|
||||||
|
qor_mbox_notify(&AudioMailBox, (void **)&wake_up, QOR_MBOX_OPTION_SEND_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void show_duration(uint32_t millisecondes)
|
||||||
|
{
|
||||||
|
uint32_t minutes, secondes, reste;
|
||||||
|
|
||||||
|
// Calcul des minutes, secondes et millisecondes
|
||||||
|
minutes = millisecondes / (60 * 1000);
|
||||||
|
reste = millisecondes % (60 * 1000);
|
||||||
|
secondes = reste / 1000;
|
||||||
|
reste = reste % 1000;
|
||||||
|
|
||||||
|
// Affichage du temps
|
||||||
|
debug_printf("Temps : %d minutes, %d secondes, %d millisecondes\r\n", minutes, secondes, reste);
|
||||||
|
}
|
||||||
|
|
||||||
|
void play_sound_file(const char *filename)
|
||||||
|
{
|
||||||
|
debug_printf("\r\n-------------------------------------------------------\r\nPlaying: out2.wav\r\n");
|
||||||
|
ost_system_stopwatch_start();
|
||||||
|
ost_audio_play(filename);
|
||||||
|
|
||||||
|
ost_audio_event_t *e = NULL;
|
||||||
|
|
||||||
|
int isPlaying = 0;
|
||||||
|
int count = 0;
|
||||||
|
uint32_t res = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
uint32_t res = qor_mbox_wait(&AudioMailBox, (void **)&e, 300); // On devrait recevoir un message toutes les 3ms (durée d'envoi d'un buffer I2S)
|
||||||
|
|
||||||
|
if (res == QOR_MBOX_OK)
|
||||||
|
{
|
||||||
|
isPlaying = ost_audio_process();
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
|
||||||
|
} while (isPlaying);
|
||||||
|
|
||||||
|
uint32_t executionTime = ost_system_stopwatch_stop();
|
||||||
|
ost_audio_stop();
|
||||||
|
|
||||||
|
debug_printf("\r\nPackets: %d\r\n", count);
|
||||||
|
show_duration(executionTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FsTask(void *args)
|
||||||
|
{
|
||||||
|
ost_fs_event_t *fs_ev = NULL;
|
||||||
|
uint32_t res = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
switch (FsState)
|
||||||
|
{
|
||||||
|
FS_PLAY_SOUND:
|
||||||
|
play_sound_file(fs_ev->filename);
|
||||||
|
FsState = FS_WAIT_FOR_EVENT;
|
||||||
|
break;
|
||||||
|
FS_DISPLAY_IMAGE:
|
||||||
|
filesystem_display_image(fs_ev->filename);
|
||||||
|
FsState = FS_WAIT_FOR_EVENT;
|
||||||
|
break;
|
||||||
|
FS_LOAD_INDEX:
|
||||||
|
filesystem_read_index_file(&OstContext);
|
||||||
|
FsState = FS_WAIT_FOR_EVENT;
|
||||||
|
break;
|
||||||
|
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:
|
||||||
|
default:
|
||||||
|
res = qor_mbox_wait(&FsMailBox, (void **)&fs_ev, 1000);
|
||||||
|
if (res == QOR_MBOX_OK)
|
||||||
|
{
|
||||||
|
// valid event, accept it
|
||||||
|
FsState = fs_ev->ev;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (;;)
|
||||||
|
// {
|
||||||
|
// ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 0);
|
||||||
|
// qor_sleep(500);
|
||||||
|
// ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 1);
|
||||||
|
// qor_sleep(500);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_task_scan_index()
|
||||||
|
{
|
||||||
|
static ost_fs_event_t ScanIndexEv = {
|
||||||
|
.ev = FS_LOAD_INDEX,
|
||||||
|
.filename = NULL};
|
||||||
|
|
||||||
|
qor_mbox_notify(&FsMailBox, (void **)&ScanIndexEv, QOR_MBOX_OPTION_SEND_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fs_task_initialize()
|
||||||
|
{
|
||||||
|
qor_mbox_init(&AudioMailBox, (void **)&AudioQueue, 10);
|
||||||
|
qor_mbox_init(&FsMailBox, (void **)&FsEventQueue, 10);
|
||||||
|
|
||||||
|
ost_audio_register_callback(audio_callback);
|
||||||
|
|
||||||
|
qor_create_thread(&FsTcb, FsTask, FsStack, sizeof(FsStack) / sizeof(FsStack[0]), FS_TASK_PRIORITY, "FsTask");
|
||||||
|
}
|
||||||
5
software/system/fs_task.h
Normal file
5
software/system/fs_task.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#ifndef FS_TASK_H
|
||||||
|
#define FS_TASK_H
|
||||||
|
|
||||||
|
void fs_task_initialize();
|
||||||
|
#endif // FS_TASK_H
|
||||||
78
software/system/hmi_task.c
Normal file
78
software/system/hmi_task.c
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
/**
|
||||||
|
* @file hmi_task.c
|
||||||
|
*
|
||||||
|
* @author your name (you@domain.com)
|
||||||
|
* @brief
|
||||||
|
* @version 0.1
|
||||||
|
* @date 2023-07-29
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ost_hal.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "qor.h"
|
||||||
|
#include "audio_player.h"
|
||||||
|
#include "filesystem.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "vm_task.h"
|
||||||
|
#include "fs_task.h"
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// DEFINITIONS
|
||||||
|
// ===========================================================================================================
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t ev;
|
||||||
|
} ost_hmi_event_t;
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// GLOBAL STORY VARIABLES
|
||||||
|
// ===========================================================================================================
|
||||||
|
|
||||||
|
static qor_tcb_t HmiTcb;
|
||||||
|
static uint32_t HmiStack[4096];
|
||||||
|
|
||||||
|
static qor_mbox_t HmiMailBox;
|
||||||
|
|
||||||
|
static ost_hmi_event_t HmiEvent;
|
||||||
|
|
||||||
|
static ost_hmi_event_t HmiQueue[10];
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// HMI TASK (user interface, buttons manager, LCD)
|
||||||
|
// ===========================================================================================================
|
||||||
|
void HmiTask(void *args)
|
||||||
|
{
|
||||||
|
|
||||||
|
ost_hmi_event_t *e = NULL;
|
||||||
|
|
||||||
|
// filesystem_display_image("/ba869e4b-03d6-4249-9202-85b4cec767a7/images/bird.qoi");
|
||||||
|
|
||||||
|
// Start by scanning the index file
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
uint32_t res = qor_mbox_wait(&HmiMailBox, (void **)&e, 1000);
|
||||||
|
|
||||||
|
if (res == QOR_MBOX_OK)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
debug_printf("H"); // pour le debug only
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hmi_task_initialize()
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
}
|
||||||
6
software/system/hmi_task.h
Normal file
6
software/system/hmi_task.h
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef HMI_TASK_H
|
||||||
|
#define HMI_TASK_H
|
||||||
|
|
||||||
|
void hmi_task_initialize();
|
||||||
|
|
||||||
|
#endif // HMI_TASK_H
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
#include "ost_hal.h"
|
#include "ost_hal.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "filesystem.h"
|
#include "filesystem.h"
|
||||||
#include "picture.h"
|
|
||||||
#include "qor.h"
|
#include "qor.h"
|
||||||
#include "rotary-button.h"
|
#include "rotary-button.h"
|
||||||
|
|
||||||
|
|
@ -12,331 +12,16 @@
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "audio_player.h"
|
|
||||||
#include "chip32_vm.h"
|
#include "chip32_vm.h"
|
||||||
#include "mini_qoi.h"
|
#include "system.h"
|
||||||
|
#include "hmi_task.h"
|
||||||
#ifdef OST_USE_FF_LIBRARY
|
#include "vm_task.h"
|
||||||
#include "ff.h"
|
#include "fs_task.h"
|
||||||
#include "diskio.h"
|
|
||||||
typedef FIL file_t;
|
|
||||||
#else
|
|
||||||
|
|
||||||
// Use standard library
|
|
||||||
typedef FILE *file_t;
|
|
||||||
typedef int FRESULT;
|
|
||||||
#define F_OK
|
|
||||||
#endif
|
|
||||||
|
|
||||||
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 ost_hal_panic()
|
void ost_hal_panic()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===========================================================================================================
|
|
||||||
// GLOBAL STORY VARIABLES
|
|
||||||
// ===========================================================================================================
|
|
||||||
static ost_context_t OstContext;
|
|
||||||
|
|
||||||
static mqoi_dec_t dec;
|
|
||||||
static mqoi_desc_t desc;
|
|
||||||
/*
|
|
||||||
if (pixel == info_header.width)
|
|
||||||
{
|
|
||||||
// enough pixels to write a line to the screen
|
|
||||||
ost_display_draw_h_line(pos.y, decompressed, palette);
|
|
||||||
// debug_printf("POS Y: %d", pos.y);
|
|
||||||
|
|
||||||
memset(decompressed, 0, sizeof(decompressed));
|
|
||||||
// ili9341_write(&pos, decompressed);
|
|
||||||
// next line...
|
|
||||||
pos.y++;
|
|
||||||
totalPixels += info_header.width;
|
|
||||||
pixel = 0;
|
|
||||||
nblines++;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
static uint8_t bmpImage[256];
|
|
||||||
|
|
||||||
static color_t line[320];
|
|
||||||
|
|
||||||
void display_image(const char *filename)
|
|
||||||
{
|
|
||||||
file_t fil;
|
|
||||||
unsigned int br;
|
|
||||||
|
|
||||||
fil = file_open(filename);
|
|
||||||
uint32_t imgW, imgH;
|
|
||||||
|
|
||||||
mqoi_desc_init(&desc);
|
|
||||||
|
|
||||||
// 1. Read header
|
|
||||||
f_read(&fil, &desc.magic[0], sizeof(mqoi_desc_t) - 1, &br);
|
|
||||||
|
|
||||||
uint8_t errn = mqoi_desc_verify(&desc, &imgW, &imgH);
|
|
||||||
|
|
||||||
if (errn)
|
|
||||||
{
|
|
||||||
debug_printf("Invalid image, code %d\n", errn);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug_printf("Image dimensions: %d, %d\n", imgW, imgH);
|
|
||||||
|
|
||||||
uint32_t start, end, pxCount = 0;
|
|
||||||
|
|
||||||
volatile mqoi_rgba_t *px;
|
|
||||||
|
|
||||||
mqoi_dec_init(&dec, imgW * imgH);
|
|
||||||
|
|
||||||
// Serial.println("starting decode...");
|
|
||||||
int index = 256; // force refill first time
|
|
||||||
int x = 0;
|
|
||||||
int y = 0;
|
|
||||||
while (!mqoi_dec_done(&dec))
|
|
||||||
{
|
|
||||||
if (index >= sizeof(bmpImage))
|
|
||||||
{
|
|
||||||
// refill buffer
|
|
||||||
f_read(&fil, bmpImage, sizeof(bmpImage), &br);
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
mqoi_dec_push(&dec, bmpImage[index++]);
|
|
||||||
|
|
||||||
while ((px = mqoi_dec_pop(&dec)) != NULL)
|
|
||||||
{
|
|
||||||
pxCount++;
|
|
||||||
|
|
||||||
line[x].r = px->r;
|
|
||||||
line[x].g = px->g;
|
|
||||||
line[x].b = px->b;
|
|
||||||
|
|
||||||
x++;
|
|
||||||
if (x >= 320)
|
|
||||||
{
|
|
||||||
ost_display_draw_h_line_rgb888(y, line);
|
|
||||||
x = 0;
|
|
||||||
y++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
f_close(&fil);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========================================================================================================
|
|
||||||
// HMI TASK (user interface, buttons manager, LCD)
|
|
||||||
// ===========================================================================================================
|
|
||||||
static qor_tcb_t HmiTcb;
|
|
||||||
static uint32_t HmiStack[4096];
|
|
||||||
|
|
||||||
static qor_mbox_t HmiMailBox;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t ev;
|
|
||||||
} ost_hmi_event_t;
|
|
||||||
|
|
||||||
static ost_hmi_event_t HmiEvent;
|
|
||||||
|
|
||||||
ost_hmi_event_t HmiQueue[10];
|
|
||||||
|
|
||||||
void HmiTask(void *args)
|
|
||||||
{
|
|
||||||
qor_mbox_init(&HmiMailBox, (void **)&HmiQueue, 10);
|
|
||||||
|
|
||||||
ost_hmi_event_t *e = NULL;
|
|
||||||
|
|
||||||
filesystem_read_index_file(&OstContext);
|
|
||||||
|
|
||||||
display_image("/ba869e4b-03d6-4249-9202-85b4cec767a7/images/bird.qoi");
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
uint32_t res = qor_mbox_wait(&HmiMailBox, (void **)&e, 1000);
|
|
||||||
|
|
||||||
if (res == QOR_MBOX_OK)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
debug_printf("H"); // pour le debug only
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========================================================================================================
|
|
||||||
// VIRTUAL MACHINE TASK
|
|
||||||
// ===========================================================================================================
|
|
||||||
static qor_tcb_t VmTcb;
|
|
||||||
static uint32_t VmStack[4096];
|
|
||||||
|
|
||||||
static qor_mbox_t VmMailBox;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t ev;
|
|
||||||
} ost_vm_event_t;
|
|
||||||
ost_vm_event_t VmQueue[10];
|
|
||||||
|
|
||||||
static ost_vm_event_t VmEvent;
|
|
||||||
|
|
||||||
static uint8_t m_rom_data[16 * 1024];
|
|
||||||
static uint8_t m_ram_data[16 * 1024];
|
|
||||||
static chip32_ctx_t m_chip32_ctx;
|
|
||||||
|
|
||||||
// Index file parameter, reference an index in the file
|
|
||||||
|
|
||||||
uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t signum)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void VmTask(void *args)
|
|
||||||
{
|
|
||||||
// VM Initialize
|
|
||||||
m_chip32_ctx.stack_size = 512;
|
|
||||||
|
|
||||||
m_chip32_ctx.rom.mem = m_rom_data;
|
|
||||||
m_chip32_ctx.rom.addr = 0;
|
|
||||||
m_chip32_ctx.rom.size = sizeof(m_rom_data);
|
|
||||||
|
|
||||||
m_chip32_ctx.ram.mem = m_ram_data;
|
|
||||||
m_chip32_ctx.ram.addr = sizeof(m_rom_data);
|
|
||||||
m_chip32_ctx.ram.size = sizeof(m_ram_data);
|
|
||||||
|
|
||||||
m_chip32_ctx.syscall = vm_syscall;
|
|
||||||
|
|
||||||
chip32_initialize(&m_chip32_ctx);
|
|
||||||
|
|
||||||
qor_mbox_init(&VmMailBox, (void **)&VmQueue, 10);
|
|
||||||
|
|
||||||
chip32_result_t run_result;
|
|
||||||
ost_vm_event_t *e = NULL;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
uint32_t res = qor_mbox_wait(&VmMailBox, (void **)&e, 300); // On devrait recevoir un message toutes les 3ms (durée d'envoi d'un buffer I2S)
|
|
||||||
|
|
||||||
if (res == QOR_MBOX_OK)
|
|
||||||
{
|
|
||||||
if (VmEvent.ev == 1)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
run_result = chip32_step(&m_chip32_ctx);
|
|
||||||
} while (run_result != VM_OK);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========================================================================================================
|
|
||||||
// AUDIO TASK
|
|
||||||
// ===========================================================================================================
|
|
||||||
static qor_tcb_t AudioTcb;
|
|
||||||
static uint32_t AudioStack[4096];
|
|
||||||
|
|
||||||
static qor_mbox_t AudioMailBox;
|
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
uint8_t ev;
|
|
||||||
} ost_audio_event_t;
|
|
||||||
|
|
||||||
static ost_audio_event_t wake_up;
|
|
||||||
|
|
||||||
ost_audio_event_t audio_queue[10];
|
|
||||||
|
|
||||||
static int dbg_state = 0;
|
|
||||||
|
|
||||||
// End of DMA transfer callback
|
|
||||||
static void audio_callback(void)
|
|
||||||
{
|
|
||||||
dbg_state = 1 - dbg_state;
|
|
||||||
qor_mbox_notify(&AudioMailBox, (void **)&wake_up, QOR_MBOX_OPTION_SEND_BACK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void show_duration(uint32_t millisecondes)
|
|
||||||
{
|
|
||||||
uint32_t minutes, secondes, reste;
|
|
||||||
|
|
||||||
// Calcul des minutes, secondes et millisecondes
|
|
||||||
minutes = millisecondes / (60 * 1000);
|
|
||||||
reste = millisecondes % (60 * 1000);
|
|
||||||
secondes = reste / 1000;
|
|
||||||
reste = reste % 1000;
|
|
||||||
|
|
||||||
// Affichage du temps
|
|
||||||
debug_printf("Temps : %d minutes, %d secondes, %d millisecondes\r\n", minutes, secondes, reste);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AudioTask(void *args)
|
|
||||||
{
|
|
||||||
// picture_show("example.bmp");
|
|
||||||
|
|
||||||
wake_up.ev = 34;
|
|
||||||
|
|
||||||
qor_mbox_init(&AudioMailBox, (void **)&audio_queue, 10);
|
|
||||||
|
|
||||||
ost_audio_register_callback(audio_callback);
|
|
||||||
|
|
||||||
static bool onetime = true;
|
|
||||||
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
debug_printf("\r\n-------------------------------------------------------\r\nPlaying: out2.wav\r\n");
|
|
||||||
ost_system_stopwatch_start();
|
|
||||||
ost_audio_play("out2.wav");
|
|
||||||
|
|
||||||
ost_audio_event_t *e = NULL;
|
|
||||||
|
|
||||||
int isPlaying = 0;
|
|
||||||
int count = 0;
|
|
||||||
do
|
|
||||||
{
|
|
||||||
uint32_t res = qor_mbox_wait(&AudioMailBox, (void **)&e, 300); // On devrait recevoir un message toutes les 3ms (durée d'envoi d'un buffer I2S)
|
|
||||||
|
|
||||||
if (res == QOR_MBOX_OK)
|
|
||||||
{
|
|
||||||
isPlaying = ost_audio_process();
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
|
|
||||||
} while (isPlaying);
|
|
||||||
|
|
||||||
uint32_t executionTime = ost_system_stopwatch_stop();
|
|
||||||
ost_audio_stop();
|
|
||||||
|
|
||||||
debug_printf("\r\nPackets: %d\r\n", count);
|
|
||||||
show_duration(executionTime);
|
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 0);
|
|
||||||
qor_sleep(500);
|
|
||||||
ost_hal_gpio_set(OST_GPIO_DEBUG_LED, 1);
|
|
||||||
qor_sleep(500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ===========================================================================================================
|
// ===========================================================================================================
|
||||||
// IDLE TASK
|
// IDLE TASK
|
||||||
// ===========================================================================================================
|
// ===========================================================================================================
|
||||||
|
|
@ -369,9 +54,9 @@ int main()
|
||||||
qor_init(125000000UL);
|
qor_init(125000000UL);
|
||||||
|
|
||||||
// 5. Initialize the tasks
|
// 5. Initialize the tasks
|
||||||
qor_create_thread(&HmiTcb, HmiTask, HmiStack, sizeof(HmiStack) / sizeof(HmiStack[0]), 1, "HmiTask"); // less priority is the HMI (user inputs and LCD)
|
hmi_task_initialize();
|
||||||
qor_create_thread(&VmTcb, VmTask, VmStack, sizeof(VmStack) / sizeof(VmStack[0]), 2, "VmTask");
|
vm_task_initialize();
|
||||||
qor_create_thread(&AudioTcb, AudioTask, AudioStack, sizeof(AudioStack) / sizeof(AudioStack[0]), 3, "AudioTask"); ///< High priority for audio
|
fs_task_initialize();
|
||||||
|
|
||||||
// 6. Start the operating system!
|
// 6. Start the operating system!
|
||||||
qor_start(&IdleTcb, IdleTask, IdleStack, 1024);
|
qor_start(&IdleTcb, IdleTask, IdleStack, 1024);
|
||||||
|
|
|
||||||
9
software/system/system.h
Normal file
9
software/system/system.h
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
#ifndef SYSTEM_H
|
||||||
|
#define SYSTEM_H
|
||||||
|
|
||||||
|
// 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
|
||||||
|
|
||||||
|
#endif // SYSTEM_H
|
||||||
156
software/system/vm_task.c
Normal file
156
software/system/vm_task.c
Normal file
|
|
@ -0,0 +1,156 @@
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "ost_hal.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "qor.h"
|
||||||
|
#include "chip32_vm.h"
|
||||||
|
#include "system.h"
|
||||||
|
#include "vm_task.h"
|
||||||
|
#include "fs_task.h"
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// DEFINITIONS
|
||||||
|
// ===========================================================================================================
|
||||||
|
#define VM_EV_NO_EVENT 0
|
||||||
|
#define VM_EV_START_STORY_EVENT 0xA1
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t ev;
|
||||||
|
const char *story_dir;
|
||||||
|
} ost_vm_event_t;
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// PRIVATE GLOBAL VARIABLES
|
||||||
|
// ===========================================================================================================
|
||||||
|
static qor_tcb_t VmTcb;
|
||||||
|
static uint32_t VmStack[4096];
|
||||||
|
static qor_mbox_t VmMailBox;
|
||||||
|
static ost_vm_event_t VmQueue[10];
|
||||||
|
|
||||||
|
static ost_vm_event_t VmStartEvent;
|
||||||
|
static uint8_t m_rom_data[16 * 1024];
|
||||||
|
static uint8_t m_ram_data[16 * 1024];
|
||||||
|
static chip32_ctx_t m_chip32_ctx;
|
||||||
|
static char CurrentStory[260]; // Current story path
|
||||||
|
static char ImageFile[260];
|
||||||
|
static char SoundFile[260];
|
||||||
|
|
||||||
|
// ===========================================================================================================
|
||||||
|
// VIRTUAL MACHINE TASK
|
||||||
|
// ===========================================================================================================
|
||||||
|
|
||||||
|
void get_file_from_memory(char *mem, uint32_t addr)
|
||||||
|
{
|
||||||
|
bool isRam = addr & 0x80000000;
|
||||||
|
addr &= 0xFFFF; // mask the RAM/ROM bit, ensure 16-bit addressing
|
||||||
|
if (isRam)
|
||||||
|
{
|
||||||
|
strcpy(&mem[0], (const char *)&m_chip32_ctx.ram.mem[addr]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(&mem[0], (const char *)&m_chip32_ctx.rom.mem[addr]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Callback from the VM
|
||||||
|
// Called inside the thread context
|
||||||
|
uint8_t vm_syscall(chip32_ctx_t *ctx, uint8_t code)
|
||||||
|
{
|
||||||
|
uint8_t retCode = SYSCALL_RET_OK;
|
||||||
|
|
||||||
|
// Media
|
||||||
|
if (code == 1) // Execute media
|
||||||
|
{
|
||||||
|
if (m_chip32_ctx.registers[R0] != 0)
|
||||||
|
{
|
||||||
|
// image file name address is in R0
|
||||||
|
// QString imageFile = m_model.BuildFullImagePath(GetFileNameFromMemory(m_chip32_ctx.registers[R0]));
|
||||||
|
// m_ostHmiDock->SetImage(imageFile);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// m_ostHmiDock->ClearImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_chip32_ctx.registers[R1] != 0)
|
||||||
|
{
|
||||||
|
// sound file name address is in R1
|
||||||
|
// QString soundFile = m_model.BuildFullSoundPath(GetFileNameFromMemory(m_chip32_ctx.registers[R1]));
|
||||||
|
// qDebug() << ", Sound: " << soundFile;
|
||||||
|
// m_model.PlaySoundFile(soundFile);
|
||||||
|
}
|
||||||
|
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||||
|
}
|
||||||
|
// WAIT EVENT bits:
|
||||||
|
// 0: block
|
||||||
|
// 1: OK button
|
||||||
|
// 2: home button
|
||||||
|
// 3: pause button
|
||||||
|
// 4: rotary left
|
||||||
|
// 5: rotary right
|
||||||
|
else if (code == 2) // Wait for event
|
||||||
|
{
|
||||||
|
// Event mask is located in R0
|
||||||
|
// optional timeout is located in R1
|
||||||
|
// if timeout is set to zero, wait for infinite and beyond
|
||||||
|
retCode = SYSCALL_RET_WAIT_EV; // set the VM in pause
|
||||||
|
}
|
||||||
|
|
||||||
|
return retCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VmTask(void *args)
|
||||||
|
{
|
||||||
|
// VM Initialize
|
||||||
|
m_chip32_ctx.stack_size = 512;
|
||||||
|
|
||||||
|
m_chip32_ctx.rom.mem = m_rom_data;
|
||||||
|
m_chip32_ctx.rom.addr = 0;
|
||||||
|
m_chip32_ctx.rom.size = sizeof(m_rom_data);
|
||||||
|
|
||||||
|
m_chip32_ctx.ram.mem = m_ram_data;
|
||||||
|
m_chip32_ctx.ram.addr = sizeof(m_rom_data);
|
||||||
|
m_chip32_ctx.ram.size = sizeof(m_ram_data);
|
||||||
|
|
||||||
|
m_chip32_ctx.syscall = vm_syscall;
|
||||||
|
|
||||||
|
chip32_result_t run_result;
|
||||||
|
ost_vm_event_t *e = NULL;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
uint32_t res = qor_mbox_wait(&VmMailBox, (void **)&e, 300); // On devrait recevoir un message toutes les 3ms (durée d'envoi d'un buffer I2S)
|
||||||
|
|
||||||
|
if (res == QOR_MBOX_OK)
|
||||||
|
{
|
||||||
|
if (VmStartEvent.ev == VM_EV_START_STORY_EVENT)
|
||||||
|
{
|
||||||
|
// Launch the execution of a story
|
||||||
|
chip32_initialize(&m_chip32_ctx);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
run_result = chip32_step(&m_chip32_ctx);
|
||||||
|
} while (run_result != VM_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_task_start_story(const char *story_directory)
|
||||||
|
{
|
||||||
|
VmStartEvent.story_dir = story_directory;
|
||||||
|
qor_mbox_notify(&VmMailBox, (void **)&VmStartEvent, QOR_MBOX_OPTION_SEND_BACK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_task_initialize()
|
||||||
|
{
|
||||||
|
VmStartEvent.ev = VM_EV_START_STORY_EVENT;
|
||||||
|
qor_mbox_init(&VmMailBox, (void **)&VmQueue, 10);
|
||||||
|
qor_create_thread(&VmTcb, VmTask, VmStack, sizeof(VmStack) / sizeof(VmStack[0]), VM_TASK_PRIORITY, "VmTask");
|
||||||
|
}
|
||||||
7
software/system/vm_task.h
Normal file
7
software/system/vm_task.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef VM_TASK_H
|
||||||
|
#define VM_TASK_H
|
||||||
|
|
||||||
|
void vm_task_start_story(const char *story_directory);
|
||||||
|
void vm_task_initialize();
|
||||||
|
|
||||||
|
#endif // VM_TASK_H
|
||||||
|
|
@ -202,6 +202,34 @@ MainWindow::MainWindow()
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(m_resourcesDock, &ResourcesDock::sigChooseTitle, [&](bool isImage) {
|
||||||
|
m_chooseFileUi.tableView->setModel(&m_resourcesDock->getModel());
|
||||||
|
m_chooseFileDialog->exec();
|
||||||
|
|
||||||
|
// Get the file choosen
|
||||||
|
QModelIndexList selection = m_chooseFileUi.tableView->selectionModel()->selectedRows();
|
||||||
|
|
||||||
|
if (selection.count() > 0)
|
||||||
|
{
|
||||||
|
// Take first
|
||||||
|
QModelIndex index = selection.at(0);
|
||||||
|
Resource res;
|
||||||
|
if (m_project.GetResourceAt(index.row(), res))
|
||||||
|
{
|
||||||
|
if (isImage)
|
||||||
|
{
|
||||||
|
m_project.SetTitleImage(res.file);
|
||||||
|
m_resourcesDock->SetTitleImage(res.file.c_str());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_project.SetTitleSound(res.file);
|
||||||
|
m_resourcesDock->SetTitleSound(res.file.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
connect(m_toolbar, &ToolBar::sigNew, this, [&]() {
|
connect(m_toolbar, &ToolBar::sigNew, this, [&]() {
|
||||||
NewProject();
|
NewProject();
|
||||||
});
|
});
|
||||||
|
|
@ -366,7 +394,7 @@ void MainWindow::BuildAll()
|
||||||
// 2. Compile the assembly to machine binary
|
// 2. Compile the assembly to machine binary
|
||||||
GenerateBinary();
|
GenerateBinary();
|
||||||
|
|
||||||
// 3. Conert all media
|
// 3. Convert all media to desired type format
|
||||||
ConvertResources();
|
ConvertResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -422,6 +450,9 @@ void MainWindow::ExitProgram()
|
||||||
void MainWindow::RefreshProjectInformation()
|
void MainWindow::RefreshProjectInformation()
|
||||||
{
|
{
|
||||||
setWindowTitle(QString("StoryTeller Editor - ") + m_project.GetProjectFilePath().c_str());
|
setWindowTitle(QString("StoryTeller Editor - ") + m_project.GetProjectFilePath().c_str());
|
||||||
|
|
||||||
|
m_resourcesDock->SetTitleImage(m_project.GetTitleImage().c_str());
|
||||||
|
m_resourcesDock->SetTitleSound(m_project.GetTitleSound().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
void MainWindow::MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
<string>Story Resources</string>
|
<string>Story Resources</string>
|
||||||
</property>
|
</property>
|
||||||
<widget class="QWidget" name="dockWidgetContents">
|
<widget class="QWidget" name="dockWidgetContents">
|
||||||
<layout class="QGridLayout" name="gridLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item row="0" column="0">
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="addSoundButton">
|
<widget class="QPushButton" name="addSoundButton">
|
||||||
|
|
@ -40,7 +40,57 @@
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="0">
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title image</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="titleImage">
|
||||||
|
<property name="text">
|
||||||
|
<string><no file !></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="chooseTitleImageButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Choose file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title sound</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="titleSound">
|
||||||
|
<property name="text">
|
||||||
|
<string><no file !></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="chooseTitleSoundButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Choose file</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
<widget class="QTableView" name="resourcesView">
|
<widget class="QTableView" name="resourcesView">
|
||||||
<property name="selectionMode">
|
<property name="selectionMode">
|
||||||
<enum>QAbstractItemView::SingleSelection</enum>
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,24 @@ ResourcesDock::ResourcesDock(StoryProject &project, ResourceModel &model)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(m_uiOstResources.chooseTitleImageButton, &QPushButton::clicked, [&](bool enable) {
|
||||||
|
emit sigChooseTitle(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(m_uiOstResources.chooseTitleSoundButton, &QPushButton::clicked, [&](bool enable) {
|
||||||
|
emit sigChooseTitle(false);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourcesDock::SetTitleImage(const QString &name)
|
||||||
|
{
|
||||||
|
m_uiOstResources.titleImage->setText(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResourcesDock::SetTitleSound(const QString &name)
|
||||||
|
{
|
||||||
|
m_uiOstResources.titleSound->setText(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,12 @@ public:
|
||||||
|
|
||||||
void SetFilterType(const QString &type) { m_proxyModel.setFilterType(type); }
|
void SetFilterType(const QString &type) { m_proxyModel.setFilterType(type); }
|
||||||
|
|
||||||
|
void SetTitleImage(const QString &name);
|
||||||
|
void SetTitleSound(const QString &name);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sigChooseTitle(bool isImage);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
StoryProject &m_project;
|
StoryProject &m_project;
|
||||||
Ui::ostResources m_uiOstResources;
|
Ui::ostResources m_uiOstResources;
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,13 @@ void StoryProject::SaveStory(const std::vector<uint8_t> &m_program)
|
||||||
std::ofstream o(m_working_dir + std::filesystem::path::preferred_separator + "story.c32", std::ios::out | std::ios::binary);
|
std::ofstream o(m_working_dir + std::filesystem::path::preferred_separator + "story.c32", std::ios::out | std::ios::binary);
|
||||||
o.write(reinterpret_cast<const char*>(m_program.data()), m_program.size());
|
o.write(reinterpret_cast<const char*>(m_program.data()), m_program.size());
|
||||||
o.close();
|
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();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StoryProject::Initialize(const std::string &file_path)
|
void StoryProject::Initialize(const std::string &file_path)
|
||||||
|
|
@ -63,6 +70,8 @@ bool StoryProject::Load(const std::string &file_path, nlohmann::json &model)
|
||||||
|
|
||||||
m_name = projectData["name"].get<std::string>();
|
m_name = projectData["name"].get<std::string>();
|
||||||
m_uuid = projectData["uuid"].get<std::string>();
|
m_uuid = projectData["uuid"].get<std::string>();
|
||||||
|
m_titleImage = projectData.value("title_image", "");
|
||||||
|
m_titleSound = projectData.value("title_sound", "");
|
||||||
|
|
||||||
if (j.contains("resources"))
|
if (j.contains("resources"))
|
||||||
{
|
{
|
||||||
|
|
@ -159,7 +168,7 @@ bool StoryProject::Load(const std::string &file_path, nlohmann::json &model)
|
||||||
void StoryProject::Save(const nlohmann::json &model)
|
void StoryProject::Save(const nlohmann::json &model)
|
||||||
{
|
{
|
||||||
nlohmann::json j;
|
nlohmann::json j;
|
||||||
j["project"] = { {"name", m_name}, {"uuid", m_uuid} };
|
j["project"] = { {"name", m_name}, {"uuid", m_uuid}, { "title_image", m_titleImage }, { "title_sound", m_titleSound } };
|
||||||
|
|
||||||
{
|
{
|
||||||
nlohmann::json resourcesData;
|
nlohmann::json resourcesData;
|
||||||
|
|
@ -267,6 +276,16 @@ std::string StoryProject::FileToConstant(const std::string &FileName, const std:
|
||||||
return "$" + f + " DC8 \"" + f + extension + "\", 8\r\n";
|
return "$" + f + " DC8 \"" + f + extension + "\", 8\r\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StoryProject::SetTitleImage(const std::string &titleImage)
|
||||||
|
{
|
||||||
|
m_titleImage = titleImage;
|
||||||
|
}
|
||||||
|
|
||||||
|
void StoryProject::SetTitleSound(const std::string &titleSound)
|
||||||
|
{
|
||||||
|
m_titleSound = titleSound;
|
||||||
|
}
|
||||||
|
|
||||||
void StoryProject::AppendResource(const Resource &res)
|
void StoryProject::AppendResource(const Resource &res)
|
||||||
{
|
{
|
||||||
m_resources.push_back(res);
|
m_resources.push_back(res);
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,12 @@ struct StoryProject
|
||||||
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
|
static void ReplaceCharacter(std::string &theString, const std::string &toFind, const std::string &toReplace);
|
||||||
static std::string FileToConstant(const std::string &FileName, const std::string &extension);
|
static std::string FileToConstant(const std::string &FileName, const std::string &extension);
|
||||||
|
|
||||||
|
void SetTitleImage(const std::string &titleImage);
|
||||||
|
void SetTitleSound(const std::string &titleSound);
|
||||||
|
|
||||||
|
std::string GetTitleImage() const { return m_titleImage; }
|
||||||
|
std::string GetTitleSound() const { return m_titleSound; }
|
||||||
|
|
||||||
// ------------- Resources Management
|
// ------------- Resources Management
|
||||||
void AppendResource(const Resource &res);
|
void AppendResource(const Resource &res);
|
||||||
bool GetResourceAt(int index, Resource &resOut);
|
bool GetResourceAt(int index, Resource &resOut);
|
||||||
|
|
@ -117,6 +123,9 @@ private:
|
||||||
std::filesystem::path m_soundsPath;
|
std::filesystem::path m_soundsPath;
|
||||||
bool m_initialized{false};
|
bool m_initialized{false};
|
||||||
|
|
||||||
|
std::string m_titleImage;
|
||||||
|
std::string m_titleSound;
|
||||||
|
|
||||||
std::vector<Resource> m_resources;
|
std::vector<Resource> m_resources;
|
||||||
std::string m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped
|
std::string m_working_dir; /// Temporary folder based on the uuid, where the archive is unzipped
|
||||||
std::string m_project_file_path; /// JSON project file
|
std::string m_project_file_path; /// JSON project file
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue