mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-11-22 10:39:20 +01:00
Merge branch 'develop' into ed64-xseries
This commit is contained in:
commit
de2cb405f2
1
Makefile
1
Makefile
@ -29,6 +29,7 @@ SRCS = \
|
||||
flashcart/64drive/64drive_ll.c \
|
||||
flashcart/64drive/64drive.c \
|
||||
flashcart/flashcart_utils.c \
|
||||
flashcart/ed64/ed64_vseries.c \
|
||||
flashcart/flashcart.c \
|
||||
flashcart/ed64/ed64x.c \
|
||||
flashcart/sc64/sc64_ll.c \
|
||||
|
23
README.md
23
README.md
@ -26,6 +26,7 @@ An open source menu for N64 flashcarts.
|
||||
* Real Time Clock support.
|
||||
* Music playback (MP3).
|
||||
* Menu sound effects.
|
||||
* N64 ROM autoload.
|
||||
|
||||
|
||||
## Documentation
|
||||
@ -49,6 +50,9 @@ An open source menu for N64 flashcarts.
|
||||
## Experimental features
|
||||
These features are subject to change:
|
||||
|
||||
### N64 ROM autoload
|
||||
To use the autoload function, while on the `N64 ROM information` display, press the `R` button on your joypad and select the `Set ROM to autoload` option. When you restart the console, it will now only load the selected ROM rather than the menu.
|
||||
NOTE: to return to the menu, hold joypad `start` button whilst powering on the console.
|
||||
|
||||
### GamePak sprites
|
||||
To use N64 `GamePak` sprites, place `PNG` files within the `sd:/menu/boxart/` folder.
|
||||
@ -60,7 +64,7 @@ These must be `PNG` files that use the following dimensions:
|
||||
* Japanese N64 GamePak boxart sprites: 112x158
|
||||
* 64DD boxart sprites: 129x112
|
||||
|
||||
They will be loaded by directories using each character of the full 4 character Game Code (as identified in the menus ROM information).
|
||||
They will be loaded by directories using each character (case-sensitive) of the full 4 character Game Code (as identified in the menu ROM information).
|
||||
i.e. for GoldenEye NTSC USA (NGEE), this would be `sd:/menu/boxart/N/G/E/E/boxart_front.png`.
|
||||
i.e. for GoldenEye PAL (NGEP), this would be `sd:/menu/boxart/N/G/E/P/boxart_front.png`.
|
||||
|
||||
@ -70,6 +74,9 @@ i.e. for GoldenEye, this would be `sd:/menu/boxart/N/G/E/boxart_front.png`.
|
||||
**Note1:** Excluding the region ID may show the wrong boxart.
|
||||
**Note2:** For future support, boxart sprites should also include: `boxart_back.png`, `boxart_top.png`, `boxart_bottom.png`, `boxart_left.png`, `boxart_right.png`.
|
||||
|
||||
As a starting point, here is a link to a boxart pack following the new structure, including `boxart_front.png` and failback images:
|
||||
* [Link](https://drive.google.com/file/d/1IpCmFqmGgGwKKmlRBxYObfFR9XywaC6n/view?usp=drive_link)
|
||||
|
||||
|
||||
#### Compatibilty mode
|
||||
If you cannot yet satisfy the correct boxart layout, The menu still has **deprecated** support for filenames containing the Game ID.
|
||||
@ -107,10 +114,20 @@ If required, you can manually adjust the file on the SD card using your computer
|
||||
* Download the latest `menu.bin` file from the [releases](https://github.com/Polprzewodnikowy/N64FlashcartMenu/releases/) page, then put it in the root directory of your SD card.
|
||||
|
||||
|
||||
### ED64 & ED64P
|
||||
### ED64 - WIP - UNTESTED AND UNSUPPORTED - USE AT OWN RISK
|
||||
Currently not supported, but work is in progress (See [PR's](https://github.com/Polprzewodnikowy/N64FlashcartMenu/pulls)).
|
||||
NOTE: The menu may be able to load ROM's but not perform saves and may break existing ones..
|
||||
|
||||
The aim is to replace [Altra64](https://github.com/networkfusion/altra64) and [ED64-UnofficialOS](https://github.com/n64-tools/ED64-UnofficialOS-binaries).
|
||||
#### ED64 (Vseries)
|
||||
The aim is to reach feature parity with [ED64-UnofficialOS](https://github.com/n64-tools/ED64-UnofficialOS-binaries) / [ED64-OfficialOS](https://krikzz.com/pub/support/everdrive-64/v2x-v3x/os-bin/).
|
||||
Download the `OS64.v64` ROM from the latest [action run - assets] and place it in the `/ED64` folder.
|
||||
|
||||
#### ED64 (X series)
|
||||
X Series support is currently awaiting fixes, in the meantime use the official [OS](https://krikzz.com/pub/support/everdrive-64/x-series/OS/) instead.
|
||||
|
||||
#### ED64 (P clone)
|
||||
Download the `OS64P.v64` ROM from the latest [action run - assets] and place it in the `/ED64P` folder.
|
||||
The aim is to reach feature parity with [Altra64](https://github.com/networkfusion/altra64)
|
||||
|
||||
|
||||
# Open source software and licenses used
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 9dd994151ae3f3709f1f80224e6b654aac8be6b4
|
||||
Subproject commit 5295016230d657cd6c7fce5b6ed4a342538e09f5
|
@ -7,41 +7,79 @@
|
||||
#ifndef BOOT_IO_H__
|
||||
#define BOOT_IO_H__
|
||||
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
/**
|
||||
* @typedef io8_t
|
||||
* @brief 8-bit volatile IO type.
|
||||
*/
|
||||
typedef volatile uint8_t io8_t;
|
||||
|
||||
/**
|
||||
* @typedef io32_t
|
||||
* @brief 32-bit volatile IO type.
|
||||
*/
|
||||
typedef volatile uint32_t io32_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Convert an address to its uncached equivalent.
|
||||
*
|
||||
* This macro takes an address and converts it to its uncached equivalent
|
||||
* by setting the appropriate bits.
|
||||
*
|
||||
* @param address The address to convert.
|
||||
* @return The uncached equivalent of the address.
|
||||
*/
|
||||
#define UNCACHED(address) ((typeof(address)) (((io32_t) (address)) | (0xA0000000UL)))
|
||||
|
||||
/** @brief Memory Structure. */
|
||||
/**
|
||||
* @brief Memory Structure.
|
||||
*
|
||||
* This structure represents the memory layout for the SP (Signal Processor),
|
||||
* containing both Data Memory (DMEM) and Instruction Memory (IMEM).
|
||||
*/
|
||||
typedef struct {
|
||||
io32_t DMEM[1024];
|
||||
io32_t IMEM[1024];
|
||||
io32_t DMEM[1024]; /**< Data Memory (DMEM) array of 1024 32-bit words. */
|
||||
io32_t IMEM[1024]; /**< Instruction Memory (IMEM) array of 1024 32-bit words. */
|
||||
} sp_mem_t;
|
||||
|
||||
/**
|
||||
* @brief Base address for SP memory.
|
||||
*/
|
||||
#define SP_MEM_BASE (0x04000000UL)
|
||||
|
||||
/**
|
||||
* @brief Pointer to the SP memory structure.
|
||||
*/
|
||||
#define SP_MEM ((sp_mem_t *) SP_MEM_BASE)
|
||||
|
||||
/** @brief SP Registers Structure. */
|
||||
/**
|
||||
* @brief SP Registers Structure.
|
||||
*
|
||||
* This structure represents the registers for the SP (Signal Processor).
|
||||
*/
|
||||
typedef struct {
|
||||
io32_t PADDR;
|
||||
io32_t MADDR;
|
||||
io32_t RD_LEN;
|
||||
io32_t WR_LEN;
|
||||
io32_t SR;
|
||||
io32_t DMA_FULL;
|
||||
io32_t DMA_BUSY;
|
||||
io32_t SEMAPHORE;
|
||||
io32_t PADDR; /**< Physical Address Register. */
|
||||
io32_t MADDR; /**< Memory Address Register. */
|
||||
io32_t RD_LEN; /**< Read Length Register. */
|
||||
io32_t WR_LEN; /**< Write Length Register. */
|
||||
io32_t SR; /**< Status Register. */
|
||||
io32_t DMA_FULL; /**< DMA Full Register. */
|
||||
io32_t DMA_BUSY; /**< DMA Busy Register. */
|
||||
io32_t SEMAPHORE; /**< Semaphore Register. */
|
||||
io32_t __reserved[0xFFF8];
|
||||
io32_t PC;
|
||||
} sp_regs_t;
|
||||
|
||||
/**
|
||||
* @brief Base address for SP registers.
|
||||
*/
|
||||
#define SP_BASE (0x04040000UL)
|
||||
|
||||
/**
|
||||
* @brief Pointer to the SP registers structure.
|
||||
*/
|
||||
#define SP ((sp_regs_t *) SP_BASE)
|
||||
|
||||
#define SP_SR_HALT (1 << 0)
|
||||
@ -85,7 +123,6 @@ typedef struct {
|
||||
#define SP_SR_CLR_SIG7 (1 << 23)
|
||||
#define SP_SR_SET_SIG7 (1 << 24)
|
||||
|
||||
|
||||
/** @brief DPC Registers Structure. */
|
||||
typedef struct {
|
||||
io32_t START;
|
||||
@ -123,7 +160,6 @@ typedef struct {
|
||||
#define DPC_SR_CLR_CMD_CTR (1 << 8)
|
||||
#define DPC_SR_CLR_CLOCK_CTR (1 << 9)
|
||||
|
||||
|
||||
/** @brief Video Interface Registers Structure. */
|
||||
typedef struct {
|
||||
/** @brief The Control Register. */
|
||||
@ -198,7 +234,6 @@ typedef struct {
|
||||
#define AI_SR_FIFO_FULL (1 << 31)
|
||||
#define AI_CR_DMA_ON (1 << 0)
|
||||
|
||||
|
||||
/** @brief Peripheral Interface Register Structure. */
|
||||
typedef struct {
|
||||
/** @brief The Memory Address. */
|
||||
@ -233,15 +268,12 @@ typedef struct {
|
||||
#define PI_SR_RESET (1 << 0)
|
||||
#define PI_SR_CLR_INTR (1 << 1)
|
||||
|
||||
|
||||
#define ROM_DDIPL_BASE (0x06000000UL)
|
||||
#define ROM_DDIPL ((io32_t *) ROM_DDIPL_BASE)
|
||||
|
||||
|
||||
#define ROM_CART_BASE (0x10000000UL)
|
||||
#define ROM_CART ((io32_t *) ROM_CART_BASE)
|
||||
|
||||
|
||||
static inline uint32_t cpu_io_read (io32_t *address) {
|
||||
io32_t *uncached = UNCACHED(address);
|
||||
uint32_t value = *uncached;
|
||||
@ -253,5 +285,4 @@ static inline void cpu_io_write (io32_t *address, uint32_t value) {
|
||||
*uncached = value;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* BOOT_IO_H__ */
|
||||
|
@ -3,37 +3,47 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* @brief VR4300 Instruction Structure
|
||||
*
|
||||
* This structure represents a VR4300 instruction, which can be of different types (R-type, I-type, J-type, etc.).
|
||||
*/
|
||||
typedef union {
|
||||
uint32_t raw;
|
||||
uint32_t raw; /**< Raw 32-bit instruction */
|
||||
|
||||
struct {
|
||||
uint32_t op : 6;
|
||||
uint32_t rs : 5;
|
||||
uint32_t rt : 5;
|
||||
uint32_t imm : 16;
|
||||
} i_type;
|
||||
uint32_t op : 6; /**< Opcode field */
|
||||
uint32_t rs : 5; /**< Source register */
|
||||
uint32_t rt : 5; /**< Target register */
|
||||
uint32_t imm : 16; /**< Immediate value */
|
||||
} i_type; /**< I-type instruction format */
|
||||
|
||||
struct {
|
||||
uint32_t op : 6;
|
||||
uint32_t target : 26;
|
||||
} j_type;
|
||||
uint32_t op : 6; /**< Opcode field */
|
||||
uint32_t target : 26; /**< Target Address field */
|
||||
} j_type; /**< J-type instruction format */
|
||||
|
||||
struct {
|
||||
uint32_t op : 6;
|
||||
uint32_t rs : 5;
|
||||
uint32_t rt : 5;
|
||||
uint32_t rd : 5;
|
||||
uint32_t sa : 5;
|
||||
uint32_t funct : 6;
|
||||
} r_type;
|
||||
uint32_t op : 6; /**< Opcode field */
|
||||
uint32_t rs : 5; /**< Source register */
|
||||
uint32_t rt : 5; /**< Target register */
|
||||
uint32_t rd : 5; /**< Destination register */
|
||||
uint32_t sa : 5; /**< Shift amount */
|
||||
uint32_t funct : 6; /**< Function field */
|
||||
} r_type; /**< Alternate R-type instruction format */
|
||||
|
||||
struct {
|
||||
uint32_t op : 6;
|
||||
uint32_t co : 1;
|
||||
uint32_t funct : 25;
|
||||
} c_type;
|
||||
uint32_t op : 6; /**< Opcode field */
|
||||
uint32_t co : 1; /**< Coprocessor operation bit */
|
||||
uint32_t funct : 25; /**< Function field */
|
||||
} c_type; /**< C-type instruction format */
|
||||
} vr4300_instruction_t;
|
||||
|
||||
/**
|
||||
* @brief VR4300 Opcode Enumeration
|
||||
*
|
||||
* Enumeration for different opcodes used in VR4300 instructions.
|
||||
*/
|
||||
typedef enum {
|
||||
OP_SPECIAL,
|
||||
OP_REGIMM,
|
||||
@ -394,4 +404,4 @@ typedef enum {
|
||||
#define I_SRL(rd, rt, sa) __ASM_R_INST(OP_SPECIAL, 0, rt, rd, sa, FUNCT_SRL)
|
||||
#define I_SW(rt, offset, base) __ASM_I_INST(OP_SW, base, rt, offset)
|
||||
|
||||
#endif
|
||||
#endif /* VR4300_ASM_H__ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
## 64drive developer notes
|
||||
# 64drive developer notes
|
||||
|
||||
### Official documentation
|
||||
|
||||
|
155
src/flashcart/ed64/ed64_vseries.c
Normal file
155
src/flashcart/ed64/ed64_vseries.c
Normal file
@ -0,0 +1,155 @@
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <fatfs/ff.h>
|
||||
#include <libdragon.h>
|
||||
|
||||
#include "utils/fs.h"
|
||||
#include "utils/utils.h"
|
||||
|
||||
#include "../flashcart_utils.h"
|
||||
#include "ed64_vseries.h"
|
||||
|
||||
typedef enum {
|
||||
ED64_V1_0 = 110,
|
||||
ED64_V2_0 = 320,
|
||||
ED64_V2_5 = 325,
|
||||
ED64_V3_0 = 330,
|
||||
} ed64_vseries_device_variant_t;
|
||||
|
||||
/* ED64 save location base address */
|
||||
#define SRAM_ADDRESS (0xA8000000)
|
||||
/* ED64 ROM location base address */
|
||||
#define ROM_ADDRESS (0xB0000000)
|
||||
|
||||
static flashcart_err_t ed64_vseries_init (void) {
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static flashcart_err_t ed64_vseries_deinit (void) {
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static ed64_vseries_device_variant_t get_cart_model() {
|
||||
ed64_vseries_device_variant_t variant = ED64_V1_0; // FIXME: check cart model from ll for better feature handling.
|
||||
return variant;
|
||||
}
|
||||
|
||||
static bool ed64_vseries_has_feature (flashcart_features_t feature) {
|
||||
bool is_model_v3 = (get_cart_model() == ED64_V3_0);
|
||||
switch (feature) {
|
||||
case FLASHCART_FEATURE_RTC: return is_model_v3 ? true : false;
|
||||
case FLASHCART_FEATURE_USB: return is_model_v3 ? true : false;
|
||||
case FLASHCART_FEATURE_AUTO_CIC: return is_model_v3 ? true : false;
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
static flashcart_err_t ed64_vseries_load_rom (char *rom_path, flashcart_progress_callback_t *progress) {
|
||||
FIL fil;
|
||||
UINT br;
|
||||
|
||||
if (f_open(&fil, strip_fs_prefix(rom_path), FA_READ) != FR_OK) {
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
fatfs_fix_file_size(&fil);
|
||||
|
||||
size_t rom_size = f_size(&fil);
|
||||
|
||||
if (rom_size > MiB(64)) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
size_t sdram_size = MiB(64);
|
||||
|
||||
size_t chunk_size = KiB(128);
|
||||
for (int offset = 0; offset < sdram_size; offset += chunk_size) {
|
||||
size_t block_size = MIN(sdram_size - offset, chunk_size);
|
||||
if (f_read(&fil, (void *) (ROM_ADDRESS + offset), block_size, &br) != FR_OK) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
if (progress) {
|
||||
progress(f_tell(&fil) / (float) (f_size(&fil)));
|
||||
}
|
||||
}
|
||||
if (f_tell(&fil) != rom_size) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
if (f_close(&fil) != FR_OK) {
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static flashcart_err_t ed64_vseries_load_file (char *file_path, uint32_t rom_offset, uint32_t file_offset) {
|
||||
FIL fil;
|
||||
UINT br;
|
||||
|
||||
if (f_open(&fil, strip_fs_prefix(file_path), FA_READ) != FR_OK) {
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
fatfs_fix_file_size(&fil);
|
||||
|
||||
size_t file_size = f_size(&fil) - file_offset;
|
||||
|
||||
if (file_size > (MiB(64) - rom_offset)) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_ARGS;
|
||||
}
|
||||
|
||||
if (f_lseek(&fil, file_offset) != FR_OK) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
if (f_read(&fil, (void *) (ROM_ADDRESS + rom_offset), file_size, &br) != FR_OK) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
if (br != file_size) {
|
||||
f_close(&fil);
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
if (f_close(&fil) != FR_OK) {
|
||||
return FLASHCART_ERR_LOAD;
|
||||
}
|
||||
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static flashcart_err_t ed64_vseries_load_save (char *save_path) {
|
||||
// FIXME: the savetype will be none.
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static flashcart_err_t ed64_vseries_set_save_type (flashcart_save_type_t save_type) {
|
||||
// FIXME: the savetype will be none.
|
||||
return FLASHCART_OK;
|
||||
}
|
||||
|
||||
static flashcart_t flashcart_ed64_vseries = {
|
||||
.init = ed64_vseries_init,
|
||||
.deinit = ed64_vseries_deinit,
|
||||
.has_feature = ed64_vseries_has_feature,
|
||||
.load_rom = ed64_vseries_load_rom,
|
||||
.load_file = ed64_vseries_load_file,
|
||||
.load_save = ed64_vseries_load_save,
|
||||
.load_64dd_ipl = NULL,
|
||||
.load_64dd_disk = NULL,
|
||||
.set_save_type = ed64_vseries_set_save_type,
|
||||
.set_save_writeback = NULL,
|
||||
};
|
||||
|
||||
|
||||
flashcart_t *ed64_vseries_get_flashcart (void) {
|
||||
return &flashcart_ed64_vseries;
|
||||
}
|
24
src/flashcart/ed64/ed64_vseries.h
Normal file
24
src/flashcart/ed64/ed64_vseries.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file ed64_vseries.h
|
||||
* @brief ED64 Vseries flashcart support
|
||||
* @ingroup flashcart
|
||||
*/
|
||||
|
||||
#ifndef FLASHCART_ED64_VSERIES_H__
|
||||
#define FLASHCART_ED64_VSERIES_H__
|
||||
|
||||
|
||||
#include "../flashcart.h"
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup ED64_Vseries
|
||||
* @{
|
||||
*/
|
||||
|
||||
flashcart_t *ed64_vseries_get_flashcart (void);
|
||||
|
||||
/** @} */ /* ED64_Vseries */
|
||||
|
||||
|
||||
#endif
|
24
src/flashcart/ed64/ed64_xseries.h
Normal file
24
src/flashcart/ed64/ed64_xseries.h
Normal file
@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file ed64xseries.h
|
||||
* @brief ED64 Xseries flashcart support
|
||||
* @ingroup flashcart
|
||||
*/
|
||||
|
||||
#ifndef FLASHCART_ED64XSERIES_H__
|
||||
#define FLASHCART_ED64XSERIES_H__
|
||||
|
||||
|
||||
#include "../flashcart.h"
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup ED64_Xseries
|
||||
* @{
|
||||
*/
|
||||
|
||||
flashcart_t *ed64xseries_get_flashcart (void);
|
||||
|
||||
/** @} */ /* ED64_Xseries */
|
||||
|
||||
|
||||
#endif
|
@ -10,6 +10,7 @@
|
||||
#include "flashcart.h"
|
||||
#include "flashcart_utils.h"
|
||||
|
||||
#include "ed64/ed64_vseries.h"
|
||||
#include "64drive/64drive.h"
|
||||
#include "ed64/ed64x.h"
|
||||
#include "sc64/sc64.h"
|
||||
@ -110,10 +111,11 @@ flashcart_err_t flashcart_init (const char **storage_prefix) {
|
||||
break;
|
||||
|
||||
case CART_EDX: // Official EverDrive 64 Series X
|
||||
flashcart = ed64x_get_flashcart();
|
||||
flashcart = ed64_xseries_get_flashcart();
|
||||
break;
|
||||
|
||||
case CART_ED: // Series V EverDrive-64 or clone
|
||||
flashcart = ed64_vseries_get_flashcart();
|
||||
break;
|
||||
|
||||
case CART_SC: // SummerCart64
|
||||
|
@ -1,4 +1,4 @@
|
||||
## SummerCart64 developer notes
|
||||
# SummerCart64 developer notes
|
||||
|
||||
### Official documentation
|
||||
|
||||
|
@ -1,109 +1,261 @@
|
||||
/**
|
||||
* @file components.h
|
||||
* @brief Menu Components
|
||||
* @brief Menu Graphical User Interface Components
|
||||
* @ingroup menu
|
||||
*/
|
||||
|
||||
#ifndef COMPONENTS_H__
|
||||
#define COMPONENTS_H__
|
||||
|
||||
|
||||
#include <libdragon.h>
|
||||
#include "menu_state.h"
|
||||
|
||||
/** @brief File image Enumeration. */
|
||||
typedef enum {
|
||||
|
||||
/** @brief Boxart image from the front */
|
||||
IMAGE_BOXART_FRONT,
|
||||
|
||||
/** @brief Boxart image from the back */
|
||||
IMAGE_BOXART_BACK,
|
||||
|
||||
/** @brief Boxart image from the top */
|
||||
IMAGE_BOXART_TOP,
|
||||
|
||||
/** @brief Boxart image from the bottom */
|
||||
IMAGE_BOXART_BOTTOM,
|
||||
|
||||
/** @brief Boxart image from the left side */
|
||||
IMAGE_BOXART_LEFT,
|
||||
|
||||
/** @brief Boxart image from the right side */
|
||||
IMAGE_BOXART_RIGHT,
|
||||
|
||||
/** @brief GamePak image from the front */
|
||||
IMAGE_GAMEPAK_FRONT,
|
||||
|
||||
/** @brief GamePak image from the back */
|
||||
IMAGE_GAMEPAK_BACK,
|
||||
|
||||
/** @brief File image thumbnail */
|
||||
IMAGE_THUMBNAIL,
|
||||
|
||||
/** @brief List end marker */
|
||||
IMAGE_TYPE_END
|
||||
|
||||
} file_image_type_t;
|
||||
|
||||
|
||||
/**
|
||||
* @addtogroup
|
||||
* @{ menu_components
|
||||
* @addtogroup menu_ui_components
|
||||
* @{
|
||||
*/
|
||||
|
||||
void component_box_draw (int x0, int y0, int x1, int y1, color_t color);
|
||||
void component_border_draw (int x0, int y0, int x1, int y1);
|
||||
void component_layout_draw (void);
|
||||
void component_progressbar_draw (int x0, int y0, int x1, int y1, float progress);
|
||||
void component_seekbar_draw (float progress);
|
||||
void component_loader_draw (float position);
|
||||
void component_scrollbar_draw (int x, int y, int width, int height, int position, int items, int visible_items);
|
||||
void component_list_scrollbar_draw (int position, int items, int visible_items);
|
||||
void component_dialog_draw (int width, int height);
|
||||
void component_messagebox_draw (char *fmt, ...);
|
||||
void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...);
|
||||
void component_actions_bar_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...);
|
||||
/**
|
||||
* @brief File image Enumeration.
|
||||
*
|
||||
* Enumeration for different types of file images used in the GUI.
|
||||
*/
|
||||
typedef enum {
|
||||
IMAGE_BOXART_FRONT, /**< Boxart image from the front */
|
||||
IMAGE_BOXART_BACK, /**< Boxart image from the back */
|
||||
IMAGE_BOXART_TOP, /**< Boxart image from the top */
|
||||
IMAGE_BOXART_BOTTOM, /**< Boxart image from the bottom */
|
||||
IMAGE_BOXART_LEFT, /**< Boxart image from the left side */
|
||||
IMAGE_BOXART_RIGHT, /**< Boxart image from the right side */
|
||||
IMAGE_GAMEPAK_FRONT, /**< GamePak image from the front */
|
||||
IMAGE_GAMEPAK_BACK, /**< GamePak image from the back */
|
||||
IMAGE_THUMBNAIL, /**< File image thumbnail */
|
||||
IMAGE_TYPE_END /**< List end marker */
|
||||
} file_image_type_t;
|
||||
|
||||
void component_background_init (char *cache_location);
|
||||
void component_background_free (void);
|
||||
void component_background_replace_image (surface_t *image);
|
||||
void component_background_draw (void);
|
||||
/**
|
||||
* @brief Draw a box component.
|
||||
*
|
||||
* @param x0 Starting x-coordinate.
|
||||
* @param y0 Starting y-coordinate.
|
||||
* @param x1 Ending x-coordinate.
|
||||
* @param y1 Ending y-coordinate.
|
||||
* @param color Color of the box.
|
||||
*/
|
||||
void component_box_draw(int x0, int y0, int x1, int y1, color_t color);
|
||||
|
||||
void component_file_list_draw (entry_t *list, int entries, int selected);
|
||||
/**
|
||||
* @brief Draw a border component.
|
||||
*
|
||||
* @param x0 Starting x-coordinate.
|
||||
* @param y0 Starting y-coordinate.
|
||||
* @param x1 Ending x-coordinate.
|
||||
* @param y1 Ending y-coordinate.
|
||||
*/
|
||||
void component_border_draw(int x0, int y0, int x1, int y1);
|
||||
|
||||
/**
|
||||
* @brief Draw the layout component.
|
||||
*/
|
||||
void component_layout_draw(void);
|
||||
|
||||
/**
|
||||
* @brief Draw a progress bar component.
|
||||
*
|
||||
* @param x0 Starting x-coordinate.
|
||||
* @param y0 Starting y-coordinate.
|
||||
* @param x1 Ending x-coordinate.
|
||||
* @param y1 Ending y-coordinate.
|
||||
* @param progress Progress value (0.0 to 1.0).
|
||||
*/
|
||||
void component_progressbar_draw(int x0, int y0, int x1, int y1, float progress);
|
||||
|
||||
/**
|
||||
* @brief Draw a seek bar component.
|
||||
*
|
||||
* @param progress Progress value (0.0 to 1.0).
|
||||
*/
|
||||
void component_seekbar_draw(float progress);
|
||||
|
||||
/**
|
||||
* @brief Draw a loader component.
|
||||
*
|
||||
* @param position Position value (0.0 to 1.0).
|
||||
*/
|
||||
void component_loader_draw(float position);
|
||||
|
||||
/**
|
||||
* @brief Draw a scrollbar component.
|
||||
*
|
||||
* @param x Starting x-coordinate.
|
||||
* @param y Starting y-coordinate.
|
||||
* @param width Width of the scrollbar.
|
||||
* @param height Height of the scrollbar.
|
||||
* @param position Current position.
|
||||
* @param items Total number of items.
|
||||
* @param visible_items Number of visible items.
|
||||
*/
|
||||
void component_scrollbar_draw(int x, int y, int width, int height, int position, int items, int visible_items);
|
||||
|
||||
/**
|
||||
* @brief Draw a list scrollbar component.
|
||||
*
|
||||
* @param position Current position.
|
||||
* @param items Total number of items.
|
||||
* @param visible_items Number of visible items.
|
||||
*/
|
||||
void component_list_scrollbar_draw(int position, int items, int visible_items);
|
||||
|
||||
/**
|
||||
* @brief Draw a dialog component.
|
||||
*
|
||||
* @param width Width of the dialog.
|
||||
* @param height Height of the dialog.
|
||||
*/
|
||||
void component_dialog_draw(int width, int height);
|
||||
|
||||
/**
|
||||
* @brief Draw a message box component.
|
||||
*
|
||||
* @param fmt Format string for the message.
|
||||
* @param ... Additional arguments for the format string.
|
||||
*/
|
||||
void component_messagebox_draw(char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Draw the main text component.
|
||||
*
|
||||
* @param align Horizontal alignment.
|
||||
* @param valign Vertical alignment.
|
||||
* @param fmt Format string for the text.
|
||||
* @param ... Additional arguments for the format string.
|
||||
*/
|
||||
void component_main_text_draw(rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Draw the actions bar text component.
|
||||
*
|
||||
* @param align Horizontal alignment.
|
||||
* @param valign Vertical alignment.
|
||||
* @param fmt Format string for the text.
|
||||
* @param ... Additional arguments for the format string.
|
||||
*/
|
||||
void component_actions_bar_text_draw(rdpq_align_t align, rdpq_valign_t valign, char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Initialize the background component.
|
||||
*
|
||||
* @param cache_location Location of the cache.
|
||||
*/
|
||||
void component_background_init(char *cache_location);
|
||||
|
||||
/**
|
||||
* @brief Free the background component resources.
|
||||
*/
|
||||
void component_background_free(void);
|
||||
|
||||
/**
|
||||
* @brief Replace the background image.
|
||||
*
|
||||
* @param image New background image.
|
||||
*/
|
||||
void component_background_replace_image(surface_t *image);
|
||||
|
||||
/**
|
||||
* @brief Draw the background component.
|
||||
*/
|
||||
void component_background_draw(void);
|
||||
|
||||
/**
|
||||
* @brief Draw the file list component.
|
||||
*
|
||||
* @param list List of entries.
|
||||
* @param entries Number of entries.
|
||||
* @param selected Index of the selected entry.
|
||||
*/
|
||||
void component_file_list_draw(entry_t *list, int entries, int selected);
|
||||
|
||||
/**
|
||||
* @brief Context menu structure.
|
||||
*/
|
||||
typedef struct component_context_menu {
|
||||
int row_count;
|
||||
int row_selected;
|
||||
bool hide_pending;
|
||||
struct component_context_menu *parent;
|
||||
struct component_context_menu *submenu;
|
||||
int row_count; /**< Number of rows in the context menu */
|
||||
int row_selected; /**< Index of the selected row */
|
||||
bool hide_pending; /**< Flag to indicate if hiding is pending */
|
||||
struct component_context_menu *parent; /**< Pointer to the parent context menu */
|
||||
struct component_context_menu *submenu; /**< Pointer to the submenu */
|
||||
struct {
|
||||
const char *text;
|
||||
void (*action) (menu_t *menu, void *arg);
|
||||
void *arg;
|
||||
struct component_context_menu *submenu;
|
||||
} list[];
|
||||
const char *text; /**< Text of the menu item */
|
||||
void (*action)(menu_t *menu, void *arg); /**< Action function for the menu item */
|
||||
void *arg; /**< Argument for the action function */
|
||||
struct component_context_menu *submenu; /**< Pointer to the submenu */
|
||||
} list[]; /**< List of menu items */
|
||||
} component_context_menu_t;
|
||||
|
||||
#define COMPONENT_CONTEXT_MENU_LIST_END { .text = NULL }
|
||||
#define COMPONENT_CONTEXT_MENU_LIST_END { .text = NULL } /**< End marker for the context menu list */
|
||||
|
||||
void component_context_menu_init (component_context_menu_t *cm);
|
||||
void component_context_menu_show (component_context_menu_t *cm);
|
||||
bool component_context_menu_process (menu_t *menu, component_context_menu_t *cm);
|
||||
void component_context_menu_draw (component_context_menu_t *cm);
|
||||
/**
|
||||
* @brief Initialize the context menu component.
|
||||
*
|
||||
* @param cm Pointer to the context menu structure.
|
||||
*/
|
||||
void component_context_menu_init(component_context_menu_t *cm);
|
||||
|
||||
/** @brief Box Art Structure. */
|
||||
/**
|
||||
* @brief Show the context menu component.
|
||||
*
|
||||
* @param cm Pointer to the context menu structure.
|
||||
*/
|
||||
void component_context_menu_show(component_context_menu_t *cm);
|
||||
|
||||
/**
|
||||
* @brief Process the context menu component.
|
||||
*
|
||||
* @param menu Pointer to the menu structure.
|
||||
* @param cm Pointer to the context menu structure.
|
||||
* @return True if the context menu was processed, false otherwise.
|
||||
*/
|
||||
bool component_context_menu_process(menu_t *menu, component_context_menu_t *cm);
|
||||
|
||||
/**
|
||||
* @brief Draw the context menu component.
|
||||
*
|
||||
* @param cm Pointer to the context menu structure.
|
||||
*/
|
||||
void component_context_menu_draw(component_context_menu_t *cm);
|
||||
|
||||
/**
|
||||
* @brief Box Art Structure.
|
||||
*/
|
||||
typedef struct {
|
||||
bool loading;
|
||||
surface_t *image;
|
||||
bool loading; /**< Flag to indicate if the box art is loading */
|
||||
surface_t *image; /**< Pointer to the box art image */
|
||||
} component_boxart_t;
|
||||
|
||||
component_boxart_t *component_boxart_init (const char *storage_prefix, char *game_code, file_image_type_t current_image_view);
|
||||
void component_boxart_free (component_boxart_t *b);
|
||||
void component_boxart_draw (component_boxart_t *b);
|
||||
/**
|
||||
* @brief Initialize the box art component.
|
||||
*
|
||||
* @param storage_prefix Prefix for the storage location.
|
||||
* @param game_code Game code for the box art.
|
||||
* @param current_image_view Current image view type.
|
||||
* @return Pointer to the initialized box art component.
|
||||
*/
|
||||
component_boxart_t *component_boxart_init(const char *storage_prefix, char *game_code, file_image_type_t current_image_view);
|
||||
|
||||
/** @} */ /* menu_components */
|
||||
/**
|
||||
* @brief Free the box art component resources.
|
||||
*
|
||||
* @param b Pointer to the box art component.
|
||||
*/
|
||||
void component_boxart_free(component_boxart_t *b);
|
||||
|
||||
/**
|
||||
* @brief Draw the box art component.
|
||||
*
|
||||
* @param b Pointer to the box art component.
|
||||
*/
|
||||
void component_boxart_draw(component_boxart_t *b);
|
||||
|
||||
#endif
|
||||
/** @} */ /* menu_ui_components */
|
||||
|
||||
#endif /* COMPONENTS_H__ */
|
||||
|
@ -151,7 +151,7 @@ void component_main_text_draw (rdpq_align_t align, rdpq_valign_t valign, char *f
|
||||
.height = LAYOUT_ACTIONS_SEPARATOR_Y - OVERSCAN_HEIGHT - (TEXT_MARGIN_VERTICAL * 2),
|
||||
.align = align,
|
||||
.valign = valign,
|
||||
.wrap = WRAP_ELLIPSES,
|
||||
.wrap = WRAP_WORD,
|
||||
.line_spacing = TEXT_LINE_SPACING_ADJUST,
|
||||
},
|
||||
FNT_DEFAULT,
|
||||
|
@ -52,7 +52,17 @@ typedef struct {
|
||||
} disk_info_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Loads disk information from the specified path.
|
||||
*
|
||||
* This function reads the disk information from the given path and populates
|
||||
* the provided disk_info structure with the relevant data.
|
||||
*
|
||||
* @param path A pointer to a path_t structure that specifies the path to the disk.
|
||||
* @param disk_info A pointer to a disk_info_t structure where the disk information will be stored.
|
||||
* @return A disk_err_t value indicating the success or failure of the operation.
|
||||
*/
|
||||
disk_err_t disk_info_load (path_t *path, disk_info_t *disk_info);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* DISK_INFO_H__ */
|
||||
|
@ -7,23 +7,39 @@
|
||||
#ifndef FONTS_H__
|
||||
#define FONTS_H__
|
||||
|
||||
/** @brief Font type enumeration. */
|
||||
/**
|
||||
* @brief Font type enumeration.
|
||||
*
|
||||
* This enumeration defines the different types of fonts that can be used
|
||||
* in the menu system.
|
||||
*/
|
||||
typedef enum {
|
||||
FNT_DEFAULT = 1,
|
||||
FNT_DEFAULT = 1, /**< Default font type */
|
||||
} menu_font_type_t;
|
||||
|
||||
/** @brief Font style enumeration. */
|
||||
/**
|
||||
* @brief Font style enumeration.
|
||||
*
|
||||
* This enumeration defines the different styles of fonts that can be used
|
||||
* in the menu system.
|
||||
*/
|
||||
typedef enum {
|
||||
STL_DEFAULT = 0,
|
||||
STL_GREEN,
|
||||
STL_BLUE,
|
||||
STL_YELLOW,
|
||||
STL_ORANGE,
|
||||
STL_GRAY,
|
||||
STL_DEFAULT = 0, /**< Default font style */
|
||||
STL_GREEN, /**< Green font style */
|
||||
STL_BLUE, /**< Blue font style */
|
||||
STL_YELLOW, /**< Yellow font style */
|
||||
STL_ORANGE, /**< Orange font style */
|
||||
STL_GRAY, /**< Gray font style */
|
||||
} menu_font_style_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize fonts.
|
||||
*
|
||||
* This function initializes the fonts used in the menu system. It can load
|
||||
* custom fonts from the specified path.
|
||||
*
|
||||
* @param custom_font_path Path to the custom font file.
|
||||
*/
|
||||
void fonts_init(char *custom_font_path);
|
||||
|
||||
void fonts_init (char *custom_font_path);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* FONTS_H__ */
|
||||
|
@ -104,6 +104,12 @@ typedef struct {
|
||||
path_t *disk_path;
|
||||
disk_info_t disk_info;
|
||||
} load;
|
||||
|
||||
struct {
|
||||
bool rom_file;
|
||||
bool disk_file;
|
||||
bool emulator_file;
|
||||
} boot_pending;
|
||||
} menu_t;
|
||||
|
||||
|
||||
|
@ -7,37 +7,166 @@
|
||||
#ifndef MP3_PLAYER_H__
|
||||
#define MP3_PLAYER_H__
|
||||
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
/** @brief MP3 file error enumeration */
|
||||
/**
|
||||
* @brief MP3 file error enumeration.
|
||||
*
|
||||
* Enumeration for different types of errors that can occur in the MP3 player.
|
||||
*/
|
||||
typedef enum {
|
||||
MP3PLAYER_OK,
|
||||
MP3PLAYER_ERR_OUT_OF_MEM,
|
||||
MP3PLAYER_ERR_IO,
|
||||
MP3PLAYER_ERR_NO_FILE,
|
||||
MP3PLAYER_ERR_INVALID_FILE,
|
||||
MP3PLAYER_OK, /**< No error */
|
||||
MP3PLAYER_ERR_OUT_OF_MEM, /**< Out of memory error */
|
||||
MP3PLAYER_ERR_IO, /**< Input/Output error */
|
||||
MP3PLAYER_ERR_NO_FILE, /**< No file found error */
|
||||
MP3PLAYER_ERR_INVALID_FILE, /**< Invalid file error */
|
||||
} mp3player_err_t;
|
||||
|
||||
/**
|
||||
* @brief Initialize the MP3 player mixer.
|
||||
*
|
||||
* This function initializes the mixer for the MP3 player.
|
||||
*/
|
||||
void mp3player_mixer_init(void);
|
||||
|
||||
void mp3player_mixer_init (void);
|
||||
mp3player_err_t mp3player_init (void);
|
||||
void mp3player_deinit (void);
|
||||
mp3player_err_t mp3player_load (char *path);
|
||||
void mp3player_unload (void);
|
||||
mp3player_err_t mp3player_process (void);
|
||||
bool mp3player_is_playing (void);
|
||||
bool mp3player_is_finished (void);
|
||||
mp3player_err_t mp3player_play (void);
|
||||
void mp3player_stop (void);
|
||||
mp3player_err_t mp3player_toggle (void);
|
||||
void mp3player_mute (bool mute);
|
||||
mp3player_err_t mp3player_seek (int seconds);
|
||||
float mp3player_get_duration (void);
|
||||
float mp3player_get_bitrate (void);
|
||||
int mp3player_get_samplerate (void);
|
||||
float mp3player_get_progress (void);
|
||||
/**
|
||||
* @brief Initialize the MP3 player.
|
||||
*
|
||||
* This function initializes the MP3 player and prepares it for playback.
|
||||
*
|
||||
* @return mp3player_err_t Error code indicating the result of the initialization.
|
||||
*/
|
||||
mp3player_err_t mp3player_init(void);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize the MP3 player.
|
||||
*
|
||||
* This function deinitializes the MP3 player and releases any resources.
|
||||
*/
|
||||
void mp3player_deinit(void);
|
||||
|
||||
#endif
|
||||
/**
|
||||
* @brief Load an MP3 file.
|
||||
*
|
||||
* This function loads an MP3 file from the specified path.
|
||||
*
|
||||
* @param path Path to the MP3 file.
|
||||
* @return mp3player_err_t Error code indicating the result of the load operation.
|
||||
*/
|
||||
mp3player_err_t mp3player_load(char *path);
|
||||
|
||||
/**
|
||||
* @brief Unload the current MP3 file.
|
||||
*
|
||||
* This function unloads the currently loaded MP3 file.
|
||||
*/
|
||||
void mp3player_unload(void);
|
||||
|
||||
/**
|
||||
* @brief Process the MP3 player.
|
||||
*
|
||||
* This function processes the MP3 player, handling playback and other operations.
|
||||
*
|
||||
* @return mp3player_err_t Error code indicating the result of the process operation.
|
||||
*/
|
||||
mp3player_err_t mp3player_process(void);
|
||||
|
||||
/**
|
||||
* @brief Check if the MP3 player is playing.
|
||||
*
|
||||
* This function checks if the MP3 player is currently playing.
|
||||
*
|
||||
* @return true if the MP3 player is playing, false otherwise.
|
||||
*/
|
||||
bool mp3player_is_playing(void);
|
||||
|
||||
/**
|
||||
* @brief Check if the MP3 player has finished playing.
|
||||
*
|
||||
* This function checks if the MP3 player has finished playing the current file.
|
||||
*
|
||||
* @return true if the MP3 player has finished playing, false otherwise.
|
||||
*/
|
||||
bool mp3player_is_finished(void);
|
||||
|
||||
/**
|
||||
* @brief Start playback of the MP3 file.
|
||||
*
|
||||
* This function starts playback of the currently loaded MP3 file.
|
||||
*
|
||||
* @return mp3player_err_t Error code indicating the result of the play operation.
|
||||
*/
|
||||
mp3player_err_t mp3player_play(void);
|
||||
|
||||
/**
|
||||
* @brief Stop playback of the MP3 file.
|
||||
*
|
||||
* This function stops playback of the currently loaded MP3 file.
|
||||
*/
|
||||
void mp3player_stop(void);
|
||||
|
||||
/**
|
||||
* @brief Toggle playback of the MP3 file.
|
||||
*
|
||||
* This function toggles playback of the currently loaded MP3 file.
|
||||
*
|
||||
* @return mp3player_err_t Error code indicating the result of the toggle operation.
|
||||
*/
|
||||
mp3player_err_t mp3player_toggle(void);
|
||||
|
||||
/**
|
||||
* @brief Mute or unmute the MP3 player.
|
||||
*
|
||||
* This function mutes or unmutes the MP3 player.
|
||||
*
|
||||
* @param mute true to mute, false to unmute.
|
||||
*/
|
||||
void mp3player_mute(bool mute);
|
||||
|
||||
/**
|
||||
* @brief Seek to a specific position in the MP3 file.
|
||||
*
|
||||
* This function seeks to a specific position in the currently loaded MP3 file.
|
||||
*
|
||||
* @param seconds Number of seconds to seek.
|
||||
* @return mp3player_err_t Error code indicating the result of the seek operation.
|
||||
*/
|
||||
mp3player_err_t mp3player_seek(int seconds);
|
||||
|
||||
/**
|
||||
* @brief Get the duration of the MP3 file.
|
||||
*
|
||||
* This function gets the duration of the currently loaded MP3 file.
|
||||
*
|
||||
* @return float Duration of the MP3 file in seconds.
|
||||
*/
|
||||
float mp3player_get_duration(void);
|
||||
|
||||
/**
|
||||
* @brief Get the bitrate of the MP3 file.
|
||||
*
|
||||
* This function gets the bitrate of the currently loaded MP3 file.
|
||||
*
|
||||
* @return float Bitrate of the MP3 file in kbps.
|
||||
*/
|
||||
float mp3player_get_bitrate(void);
|
||||
|
||||
/**
|
||||
* @brief Get the sample rate of the MP3 file.
|
||||
*
|
||||
* This function gets the sample rate of the currently loaded MP3 file.
|
||||
*
|
||||
* @return int Sample rate of the MP3 file in Hz.
|
||||
*/
|
||||
int mp3player_get_samplerate(void);
|
||||
|
||||
/**
|
||||
* @brief Get the current playback progress.
|
||||
*
|
||||
* This function gets the current playback progress of the MP3 file.
|
||||
*
|
||||
* @return float Current playback progress as a percentage (0.0 to 100.0).
|
||||
*/
|
||||
float mp3player_get_progress(void);
|
||||
|
||||
#endif /* MP3_PLAYER_H__ */
|
||||
|
@ -7,27 +7,68 @@
|
||||
#ifndef PNG_DECODER_H__
|
||||
#define PNG_DECODER_H__
|
||||
|
||||
|
||||
#include <surface.h>
|
||||
|
||||
|
||||
/** @brief PNG decoder errors */
|
||||
/**
|
||||
* @brief PNG decoder errors
|
||||
*
|
||||
* Enumeration for different types of errors that can occur in the PNG decoder.
|
||||
*/
|
||||
typedef enum {
|
||||
PNG_OK,
|
||||
PNG_ERR_INT,
|
||||
PNG_ERR_BUSY,
|
||||
PNG_ERR_OUT_OF_MEM,
|
||||
PNG_ERR_NO_FILE,
|
||||
PNG_ERR_BAD_FILE,
|
||||
PNG_OK, /**< No error */
|
||||
PNG_ERR_INT, /**< Internal error */
|
||||
PNG_ERR_BUSY, /**< Decoder is busy */
|
||||
PNG_ERR_OUT_OF_MEM, /**< Out of memory error */
|
||||
PNG_ERR_NO_FILE, /**< No file found error */
|
||||
PNG_ERR_BAD_FILE, /**< Bad file error */
|
||||
} png_err_t;
|
||||
|
||||
/**
|
||||
* @brief PNG decoder callback type.
|
||||
*
|
||||
* This typedef defines the callback function type used by the PNG decoder.
|
||||
*
|
||||
* @param err Error code indicating the result of the decoding process.
|
||||
* @param decoded_image Pointer to the decoded image surface.
|
||||
* @param callback_data User-defined data passed to the callback function.
|
||||
*/
|
||||
typedef void png_callback_t (png_err_t err, surface_t *decoded_image, void *callback_data);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Start the PNG decoding process.
|
||||
*
|
||||
* This function starts the PNG decoding process for the specified file.
|
||||
*
|
||||
* @param path Path to the PNG file.
|
||||
* @param max_width Maximum width of the decoded image.
|
||||
* @param max_height Maximum height of the decoded image.
|
||||
* @param callback Callback function to be called when decoding is complete.
|
||||
* @param callback_data User-defined data to be passed to the callback function.
|
||||
* @return png_err_t Error code indicating the result of the start operation.
|
||||
*/
|
||||
png_err_t png_decoder_start (char *path, int max_width, int max_height, png_callback_t *callback, void *callback_data);
|
||||
|
||||
/**
|
||||
* @brief Abort the PNG decoding process.
|
||||
*
|
||||
* This function aborts the ongoing PNG decoding process.
|
||||
*/
|
||||
void png_decoder_abort (void);
|
||||
|
||||
/**
|
||||
* @brief Get the progress of the PNG decoding process.
|
||||
*
|
||||
* This function returns the current progress of the PNG decoding process as a percentage.
|
||||
*
|
||||
* @return float Current progress of the decoding process (0.0 to 100.0).
|
||||
*/
|
||||
float png_decoder_get_progress (void);
|
||||
|
||||
/**
|
||||
* @brief Poll the PNG decoder.
|
||||
*
|
||||
* This function polls the PNG decoder to handle any ongoing decoding tasks.
|
||||
*/
|
||||
void png_decoder_poll (void);
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* PNG_DECODER_H__ */
|
||||
|
@ -14,6 +14,9 @@ static settings_t init = {
|
||||
.default_directory = "/",
|
||||
.use_saves_folder = true,
|
||||
.sound_enabled = true,
|
||||
.rom_autoload_enabled = false,
|
||||
.rom_autoload_path = "",
|
||||
.rom_autoload_filename = "",
|
||||
|
||||
/* Beta feature flags (should always init to off) */
|
||||
.bgm_enabled = false,
|
||||
@ -41,6 +44,10 @@ void settings_load (settings_t *settings) {
|
||||
settings->use_saves_folder = mini_get_bool(ini, "menu", "use_saves_folder", init.use_saves_folder);
|
||||
settings->sound_enabled = mini_get_bool(ini, "menu", "sound_enabled", init.sound_enabled);
|
||||
|
||||
settings->rom_autoload_enabled = mini_get_bool(ini, "menu", "autoload_rom_enabled", init.rom_autoload_enabled);
|
||||
settings->rom_autoload_path = strdup(mini_get_string(ini, "autoload", "rom_path", init.rom_autoload_path));
|
||||
settings->rom_autoload_filename = strdup(mini_get_string(ini, "autoload", "rom_filename", init.rom_autoload_filename));
|
||||
|
||||
/* Beta feature flags, they might not be in the file */
|
||||
settings->bgm_enabled = mini_get_bool(ini, "menu_beta_flag", "bgm_enabled", init.bgm_enabled);
|
||||
settings->rumble_enabled = mini_get_bool(ini, "menu_beta_flag", "rumble_enabled", init.rumble_enabled);
|
||||
@ -56,6 +63,9 @@ void settings_save (settings_t *settings) {
|
||||
mini_set_string(ini, "menu", "default_directory", settings->default_directory);
|
||||
mini_set_bool(ini, "menu", "use_saves_folder", settings->use_saves_folder);
|
||||
mini_set_bool(ini, "menu", "sound_enabled", settings->sound_enabled);
|
||||
mini_set_bool(ini, "menu", "autoload_rom_enabled", settings->rom_autoload_enabled);
|
||||
mini_set_string(ini, "autoload", "rom_path", settings->rom_autoload_path);
|
||||
mini_set_string(ini, "autoload", "rom_filename", settings->rom_autoload_filename);
|
||||
|
||||
/* Beta feature flags, they should not save until production ready! */
|
||||
// mini_set_bool(ini, "menu_beta_flag", "bgm_enabled", settings->bgm_enabled);
|
||||
|
@ -30,6 +30,16 @@ typedef struct {
|
||||
|
||||
/** @brief Enable rumble feedback */
|
||||
bool rumble_enabled;
|
||||
|
||||
/** @brief Enable the ability to bypass the menu and instantly load a ROM */
|
||||
bool rom_autoload_enabled;
|
||||
|
||||
/** @brief A path to the autoloaded ROM */
|
||||
char *rom_autoload_path;
|
||||
|
||||
/** @brief A filename of the autoloaded ROM */
|
||||
char *rom_autoload_filename;
|
||||
|
||||
} settings_t;
|
||||
|
||||
|
||||
@ -40,5 +50,4 @@ void settings_load (settings_t *settings);
|
||||
/** @brief The settings to save */
|
||||
void settings_save (settings_t *settings);
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -9,28 +9,46 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#define SOUND_MP3_PLAYER_CHANNEL (0)
|
||||
#define SOUND_SFX_CHANNEL (2)
|
||||
#define SOUND_MP3_PLAYER_CHANNEL (0) /**< Channel for MP3 player sound */
|
||||
#define SOUND_SFX_CHANNEL (2) /**< Channel for sound effects */
|
||||
|
||||
/**
|
||||
* @brief Enumeration of available sound effects for menu interactions.
|
||||
*
|
||||
* This enumeration defines the different sound effects that can be used
|
||||
* for menu interactions.
|
||||
*/
|
||||
typedef enum {
|
||||
SFX_CURSOR,
|
||||
SFX_ERROR,
|
||||
SFX_ENTER,
|
||||
SFX_EXIT,
|
||||
SFX_SETTING,
|
||||
SFX_CURSOR, /**< Sound effect for cursor movement */
|
||||
SFX_ERROR, /**< Sound effect for error */
|
||||
SFX_ENTER, /**< Sound effect for entering a menu */
|
||||
SFX_EXIT, /**< Sound effect for exiting a menu */
|
||||
SFX_SETTING, /**< Sound effect for changing a setting */
|
||||
} sound_effect_t;
|
||||
|
||||
|
||||
void sound_init_default (void);
|
||||
void sound_init_mp3_playback (void);
|
||||
/**
|
||||
* @brief Initialize the default sound system.
|
||||
*
|
||||
* This function initializes the default sound system, setting up
|
||||
* necessary resources and configurations.
|
||||
*/
|
||||
void sound_init_default(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize sound effects system.
|
||||
* @brief Initialize the MP3 playback system.
|
||||
*
|
||||
* This function initializes the MP3 playback system, preparing it
|
||||
* for playing MP3 files.
|
||||
*/
|
||||
void sound_init_sfx (void);
|
||||
void sound_init_mp3_playback(void);
|
||||
|
||||
/**
|
||||
* @brief Initialize the sound effects system.
|
||||
*
|
||||
* This function initializes the sound effects system, setting up
|
||||
* necessary resources and configurations for playing sound effects.
|
||||
*/
|
||||
void sound_init_sfx(void);
|
||||
|
||||
/**
|
||||
* @brief Enable or disable sound effects.
|
||||
@ -46,4 +64,4 @@ void sound_play_effect(sound_effect_t sfx);
|
||||
void sound_deinit (void);
|
||||
void sound_poll (void);
|
||||
|
||||
#endif
|
||||
#endif /* SOUND_H__ */
|
||||
|
@ -2,20 +2,36 @@
|
||||
* @file usb_comm.h
|
||||
* @brief USB communication subsystem
|
||||
* @ingroup menu
|
||||
*
|
||||
* This file contains the declarations for the USB communication subsystem
|
||||
* used in the menu system.
|
||||
*/
|
||||
|
||||
#ifndef USB_COMM_H__
|
||||
#define USB_COMM_H__
|
||||
|
||||
|
||||
#include "menu_state.h"
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
void usb_comm_poll (menu_t *menu);
|
||||
/**
|
||||
* @brief Poll the USB communication subsystem.
|
||||
*
|
||||
* This function polls the USB communication subsystem to handle any
|
||||
* incoming or outgoing data. It is only available in debug builds.
|
||||
*
|
||||
* @param menu Pointer to the menu structure.
|
||||
*/
|
||||
void usb_comm_poll(menu_t *menu);
|
||||
#else
|
||||
/**
|
||||
* @brief Poll the USB communication subsystem (no-op in release builds).
|
||||
*
|
||||
* This macro is a no-op in release builds, where USB communication polling
|
||||
* is disabled.
|
||||
*
|
||||
* @param menu Pointer to the menu structure.
|
||||
*/
|
||||
#define usb_comm_poll(menu)
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
#endif /* USB_COMM_H__ */
|
||||
|
@ -5,8 +5,7 @@
|
||||
#include "views.h"
|
||||
|
||||
|
||||
static bool load_pending;
|
||||
static bool load_rom;
|
||||
static bool load_disk_with_rom;
|
||||
static component_boxart_t *boxart;
|
||||
|
||||
|
||||
@ -31,11 +30,11 @@ static char *format_disk_region (disk_region_t region) {
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.enter) {
|
||||
load_pending = true;
|
||||
load_rom = false;
|
||||
menu->boot_pending.disk_file = true;
|
||||
load_disk_with_rom = false;
|
||||
} else if (menu->actions.options && menu->load.rom_path) {
|
||||
load_pending = true;
|
||||
load_rom = true;
|
||||
menu->boot_pending.disk_file = true;
|
||||
load_disk_with_rom = true;
|
||||
sound_play_effect(SFX_SETTING);
|
||||
} else if (menu->actions.back) {
|
||||
sound_play_effect(SFX_EXIT);
|
||||
@ -48,7 +47,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_background_draw();
|
||||
|
||||
if (load_pending) {
|
||||
if (menu->boot_pending.disk_file) {
|
||||
component_loader_draw(0.0f);
|
||||
} else {
|
||||
component_layout_draw();
|
||||
@ -119,7 +118,7 @@ static void draw_progress (float progress) {
|
||||
static void load (menu_t *menu) {
|
||||
cart_load_err_t err;
|
||||
|
||||
if (menu->load.rom_path && load_rom) {
|
||||
if (menu->load.rom_path && load_disk_with_rom) {
|
||||
err = cart_load_n64_rom_and_save(menu, draw_progress);
|
||||
if (err != CART_LOAD_OK) {
|
||||
menu_show_error(menu, cart_load_convert_error_message(err));
|
||||
@ -135,7 +134,7 @@ static void load (menu_t *menu) {
|
||||
|
||||
menu->next_mode = MENU_MODE_BOOT;
|
||||
|
||||
if (load_rom) {
|
||||
if (load_disk_with_rom) {
|
||||
menu->boot_params->device_type = BOOT_DEVICE_TYPE_ROM;
|
||||
menu->boot_params->detect_cic_seed = rom_info_get_cic_seed(&menu->load.rom_info, &menu->boot_params->cic_seed);
|
||||
switch (rom_info_get_tv_type(&menu->load.rom_info)) {
|
||||
@ -163,13 +162,14 @@ void view_load_disk_init (menu_t *menu) {
|
||||
menu->load.disk_path = NULL;
|
||||
}
|
||||
|
||||
load_pending = false;
|
||||
menu->boot_pending.disk_file = false;
|
||||
|
||||
menu->load.disk_path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
|
||||
disk_err_t err = disk_info_load(menu->load.disk_path, &menu->load.disk_info);
|
||||
if (err != DISK_OK) {
|
||||
menu_show_error(menu, convert_error_message(err));
|
||||
return;
|
||||
}
|
||||
|
||||
boxart = component_boxart_init(menu->storage_prefix, menu->load.disk_info.id, IMAGE_BOXART_FRONT);
|
||||
@ -180,8 +180,8 @@ void view_load_disk_display (menu_t *menu, surface_t *display) {
|
||||
|
||||
draw(menu, display);
|
||||
|
||||
if (load_pending) {
|
||||
load_pending = false;
|
||||
if (menu->boot_pending.disk_file) {
|
||||
menu->boot_pending.disk_file = false;
|
||||
load(menu);
|
||||
}
|
||||
|
||||
|
@ -11,7 +11,6 @@ static const char *emu_gameboy_rom_extensions[] = { "gb", NULL };
|
||||
static const char *emu_gameboy_color_rom_extensions[] = { "gbc", NULL };
|
||||
static const char *emu_sega_8bit_rom_extensions[] = { "sms", "gg", "sg", NULL };
|
||||
|
||||
static bool load_pending;
|
||||
static cart_load_emu_type_t emu_type;
|
||||
|
||||
static char *format_emulator_name (cart_load_emu_type_t emulator_info) {
|
||||
@ -34,7 +33,7 @@ static char *format_emulator_name (cart_load_emu_type_t emulator_info) {
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.enter) {
|
||||
load_pending = true;
|
||||
menu->boot_pending.emulator_file = true;
|
||||
} else if (menu->actions.back) {
|
||||
sound_play_effect(SFX_EXIT);
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
@ -46,7 +45,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_background_draw();
|
||||
|
||||
if (load_pending) {
|
||||
if (menu->boot_pending.emulator_file) {
|
||||
component_loader_draw(0.0f);
|
||||
} else {
|
||||
component_layout_draw();
|
||||
@ -107,7 +106,7 @@ static void load (menu_t *menu) {
|
||||
|
||||
|
||||
void view_load_emulator_init (menu_t *menu) {
|
||||
load_pending = false;
|
||||
menu->boot_pending.emulator_file = false;
|
||||
|
||||
path_t *path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
|
||||
@ -133,8 +132,8 @@ void view_load_emulator_display (menu_t *menu, surface_t *display) {
|
||||
|
||||
draw(menu, display);
|
||||
|
||||
if (load_pending) {
|
||||
load_pending = false;
|
||||
if (menu->boot_pending.emulator_file) {
|
||||
menu->boot_pending.emulator_file = false;
|
||||
load(menu);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
#include "boot/boot.h"
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
#include <string.h>
|
||||
#include "utils/fs.h"
|
||||
|
||||
static bool show_extra_info_message = false;
|
||||
static bool load_pending;
|
||||
static component_boxart_t *boxart;
|
||||
|
||||
|
||||
static char *convert_error_message (rom_err_t err) {
|
||||
switch (err) {
|
||||
case ROM_ERR_LOAD_IO: return "I/O error during loading ROM information and/or options";
|
||||
@ -145,6 +145,17 @@ static void set_tv_type (menu_t *menu, void *arg) {
|
||||
menu->browser.reload = true;
|
||||
}
|
||||
|
||||
static void set_autoload_type (menu_t *menu, void *arg) {
|
||||
free(menu->settings.rom_autoload_path);
|
||||
menu->settings.rom_autoload_path = strdup(strip_fs_prefix(path_get(menu->browser.directory)));
|
||||
free(menu->settings.rom_autoload_filename);
|
||||
menu->settings.rom_autoload_filename = strdup(menu->browser.entry->name);
|
||||
// FIXME: add a confirmation box here! (press start on reboot)
|
||||
menu->settings.rom_autoload_enabled = true;
|
||||
settings_save(&menu->settings);
|
||||
menu->browser.reload = true;
|
||||
}
|
||||
|
||||
static component_context_menu_t set_cic_type_context_menu = { .list = {
|
||||
{.text = "Automatic", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_AUTOMATIC) },
|
||||
{.text = "CIC-6101", .action = set_cic_type, .arg = (void *) (ROM_CIC_TYPE_6101) },
|
||||
@ -187,6 +198,7 @@ static component_context_menu_t options_context_menu = { .list = {
|
||||
{ .text = "Set CIC Type", .submenu = &set_cic_type_context_menu },
|
||||
{ .text = "Set Save Type", .submenu = &set_save_type_context_menu },
|
||||
{ .text = "Set TV Type", .submenu = &set_tv_type_context_menu },
|
||||
{ .text = "Set ROM to autoload", .action = set_autoload_type },
|
||||
COMPONENT_CONTEXT_MENU_LIST_END,
|
||||
}};
|
||||
|
||||
@ -196,7 +208,7 @@ static void process (menu_t *menu) {
|
||||
}
|
||||
|
||||
if (menu->actions.enter) {
|
||||
load_pending = true;
|
||||
menu->boot_pending.rom_file = true;
|
||||
} else if (menu->actions.back) {
|
||||
sound_play_effect(SFX_EXIT);
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
@ -218,7 +230,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_background_draw();
|
||||
|
||||
if (load_pending) {
|
||||
if (menu->boot_pending.rom_file) {
|
||||
component_loader_draw(0.0f);
|
||||
} else {
|
||||
component_layout_draw();
|
||||
@ -342,14 +354,14 @@ static void deinit (void) {
|
||||
|
||||
|
||||
void view_load_rom_init (menu_t *menu) {
|
||||
load_pending = false;
|
||||
if (!menu->settings.rom_autoload_enabled) {
|
||||
if (menu->load.rom_path) {
|
||||
path_free(menu->load.rom_path);
|
||||
}
|
||||
|
||||
if (menu->load.rom_path) {
|
||||
path_free(menu->load.rom_path);
|
||||
menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
}
|
||||
|
||||
menu->load.rom_path = path_clone_push(menu->browser.directory, menu->browser.entry->name);
|
||||
|
||||
rom_err_t err = rom_info_load(menu->load.rom_path, &menu->load.rom_info);
|
||||
if (err != ROM_OK) {
|
||||
path_free(menu->load.rom_path);
|
||||
@ -358,9 +370,10 @@ void view_load_rom_init (menu_t *menu) {
|
||||
return;
|
||||
}
|
||||
|
||||
boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT);
|
||||
|
||||
component_context_menu_init(&options_context_menu);
|
||||
if (!menu->settings.rom_autoload_enabled) {
|
||||
boxart = component_boxart_init(menu->storage_prefix, menu->load.rom_info.game_code, IMAGE_BOXART_FRONT);
|
||||
component_context_menu_init(&options_context_menu);
|
||||
}
|
||||
}
|
||||
|
||||
void view_load_rom_display (menu_t *menu, surface_t *display) {
|
||||
@ -368,8 +381,8 @@ void view_load_rom_display (menu_t *menu, surface_t *display) {
|
||||
|
||||
draw(menu, display);
|
||||
|
||||
if (load_pending) {
|
||||
load_pending = false;
|
||||
if (menu->boot_pending.rom_file) {
|
||||
menu->boot_pending.rom_file = false;
|
||||
load(menu);
|
||||
}
|
||||
|
||||
|
@ -1,26 +1,165 @@
|
||||
#include <time.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <libdragon.h>
|
||||
#include <sys/time.h>
|
||||
#include "../sound.h"
|
||||
#include "views.h"
|
||||
|
||||
// FIXME: add implementation!
|
||||
// struct {
|
||||
// uint16_t seconds;
|
||||
// uint16_t minutes;
|
||||
// uint16_t hours;
|
||||
// uint16_t day;
|
||||
// uint16_t month;
|
||||
// uint16_t year;
|
||||
// } adjusted_datetime;
|
||||
#define MAX(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a > _b ? _a : _b; })
|
||||
#define MIN(a,b) ({ typeof(a) _a = a; typeof(b) _b = b; _a < _b ? _a : _b; })
|
||||
#define CLAMP(x, min, max) (MIN(MAX((x), (min)), (max)))
|
||||
|
||||
// static void save_adjusted_datetime () {
|
||||
#define YEAR_MIN 1996
|
||||
#define YEAR_MAX 2095
|
||||
|
||||
// }
|
||||
typedef enum {
|
||||
RTC_EDIT_YEAR,
|
||||
RTC_EDIT_MONTH,
|
||||
RTC_EDIT_DAY,
|
||||
RTC_EDIT_HOUR,
|
||||
RTC_EDIT_MIN,
|
||||
RTC_EDIT_SEC,
|
||||
} rtc_field_t;
|
||||
|
||||
static const char* const DAYS_OF_WEEK[7] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
|
||||
|
||||
static struct tm rtc_tm = {0};
|
||||
static bool is_editing_mode;
|
||||
static rtc_field_t editing_field_type;
|
||||
|
||||
int wrap( uint16_t val, uint16_t min, uint16_t max ) {
|
||||
if( val < min ) return max;
|
||||
if( val > max ) return min;
|
||||
return val;
|
||||
}
|
||||
|
||||
rtc_time_t rtc_time_from_tm( struct tm *time ) {
|
||||
return(rtc_time_t){
|
||||
.year = CLAMP(time->tm_year + 1900, YEAR_MIN, YEAR_MAX),
|
||||
.month = CLAMP(time->tm_mon, 1, 12),
|
||||
.day = CLAMP(time->tm_mday, 1, 31),
|
||||
.hour = CLAMP(time->tm_hour, 0, 23),
|
||||
.min = CLAMP(time->tm_min, 0, 59),
|
||||
.sec = CLAMP(time->tm_sec, 0, 59),
|
||||
.week_day = CLAMP(time->tm_wday, 0, 6),
|
||||
};
|
||||
}
|
||||
|
||||
void adjust_rtc_time( struct tm *t, int incr ) {
|
||||
switch(editing_field_type)
|
||||
{
|
||||
case RTC_EDIT_YEAR:
|
||||
t->tm_year = wrap( t->tm_year + incr, YEAR_MIN - 1900, YEAR_MAX - 1900 );
|
||||
break;
|
||||
case RTC_EDIT_MONTH:
|
||||
t->tm_mon = wrap( t->tm_mon + incr, 0, 11 );
|
||||
break;
|
||||
case RTC_EDIT_DAY:
|
||||
t->tm_mday = wrap( t->tm_mday + incr, 1, 31 );
|
||||
break;
|
||||
case RTC_EDIT_HOUR:
|
||||
t->tm_hour = wrap( t->tm_hour + incr, 0, 23 );
|
||||
break;
|
||||
case RTC_EDIT_MIN:
|
||||
t->tm_min = wrap( t->tm_min + incr, 0, 59 );
|
||||
break;
|
||||
case RTC_EDIT_SEC:
|
||||
t->tm_sec = wrap( t->tm_sec + incr, 0, 59 );
|
||||
break;
|
||||
}
|
||||
// Recalculate day-of-week and day-of-year
|
||||
time_t timestamp = mktime( t );
|
||||
*t = *gmtime( ×tamp );
|
||||
}
|
||||
|
||||
void component_editdatetime_draw ( struct tm t, rtc_field_t selected_field ) {
|
||||
// FIXME: move this to components.c once improved.
|
||||
/* Format RTC date/time as strings */
|
||||
char full_dt[30];
|
||||
char current_selection_chars[30];
|
||||
|
||||
snprintf( full_dt, sizeof(full_dt), ">%04d|%02d|%02d|%02d|%02d|%02d< %s",
|
||||
t.tm_year + 1900,
|
||||
t.tm_mon + 1,
|
||||
t.tm_mday,
|
||||
t.tm_hour,
|
||||
t.tm_min,
|
||||
t.tm_sec,
|
||||
DAYS_OF_WEEK[t.tm_wday]
|
||||
);
|
||||
|
||||
switch(selected_field)
|
||||
{
|
||||
// Note: for what ever reason, hat chars need to be duplicated to display correctly. This will be solved when there is a decent UI for it.
|
||||
case RTC_EDIT_YEAR:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "*^^^^^^^^********************");
|
||||
break;
|
||||
case RTC_EDIT_MONTH:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "******^^^^*****************");
|
||||
break;
|
||||
case RTC_EDIT_DAY:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "*********^^^^**************");
|
||||
break;
|
||||
case RTC_EDIT_HOUR:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "************^^^^***********");
|
||||
break;
|
||||
case RTC_EDIT_MIN:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "***************^^^^********");
|
||||
break;
|
||||
case RTC_EDIT_SEC:
|
||||
snprintf( current_selection_chars, sizeof(current_selection_chars), "******************^^^^*****");
|
||||
break;
|
||||
}
|
||||
component_messagebox_draw(
|
||||
"|YYYY|MM|DD|HH|MM|SS| DOW\n%s\n%s\n", full_dt, current_selection_chars);
|
||||
}
|
||||
|
||||
static void process (menu_t *menu) {
|
||||
if (menu->actions.back) {
|
||||
if (menu->actions.back && !is_editing_mode) {
|
||||
sound_play_effect(SFX_EXIT);
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
}
|
||||
else if (menu->actions.enter && !is_editing_mode && menu->current_time >= 0) {
|
||||
rtc_tm = *gmtime(&menu->current_time);
|
||||
is_editing_mode = true;
|
||||
}
|
||||
|
||||
if (is_editing_mode) {
|
||||
if (menu->actions.go_left) {
|
||||
if ( editing_field_type <= RTC_EDIT_YEAR ) { editing_field_type = RTC_EDIT_SEC; }
|
||||
else { editing_field_type = editing_field_type - 1; }
|
||||
}
|
||||
else if (menu->actions.go_right) {
|
||||
if ( editing_field_type >= RTC_EDIT_SEC ) { editing_field_type = RTC_EDIT_YEAR; }
|
||||
else { editing_field_type = editing_field_type + 1; }
|
||||
}
|
||||
else if (menu->actions.go_up) {
|
||||
adjust_rtc_time( &rtc_tm, +1 );
|
||||
}
|
||||
else if (menu->actions.go_down) {
|
||||
adjust_rtc_time( &rtc_tm, -1 );
|
||||
}
|
||||
else if (menu->actions.options) { // R button = save
|
||||
if(rtc_is_writable()) {
|
||||
// FIXME: settimeofday is not available in libdragon yet.
|
||||
// struct timeval new_time = { .tv_sec = mktime(&rtc_tm) };
|
||||
// int res = settimeofday(&new_time, NULL);
|
||||
|
||||
rtc_time_t rtc_time = rtc_time_from_tm(&rtc_tm);
|
||||
int res = rtc_set(&rtc_time);
|
||||
if (res != 1) {
|
||||
menu_show_error(menu, "Failed to set RTC time");
|
||||
}
|
||||
}
|
||||
else {
|
||||
menu_show_error(menu, "RTC is not writable");
|
||||
}
|
||||
is_editing_mode = false;
|
||||
}
|
||||
else if (menu->actions.back) { // cancel
|
||||
is_editing_mode = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void draw (menu_t *menu, surface_t *d) {
|
||||
@ -30,36 +169,74 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
component_layout_draw();
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"ADJUST REAL TIME CLOCK\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"To set the date and time, please use the PC terminal\n"
|
||||
"application and set via USB,\n or a N64 game with RTC support.\n\n"
|
||||
"Current date & time: %s\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n"
|
||||
);
|
||||
if (!is_editing_mode) {
|
||||
if( menu->current_time >= 0 ) {
|
||||
|
||||
component_main_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"\n"
|
||||
);
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"ADJUST REAL TIME CLOCK\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"To set the RTC date and time, Press A.\n"
|
||||
"You can also use the PC terminal application via USB,\n"
|
||||
"or even an N64 game with RTC support.\n"
|
||||
"\n"
|
||||
"Current date & time: %s\n"
|
||||
"\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown"
|
||||
);
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"A: Change\n"
|
||||
"B: Back"
|
||||
);
|
||||
}
|
||||
else {
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n" // "A: Save\n"
|
||||
"B: Back"
|
||||
);
|
||||
component_main_text_draw(
|
||||
ALIGN_CENTER, VALIGN_TOP,
|
||||
"ADJUST REAL TIME CLOCK\n"
|
||||
"\n"
|
||||
"\n"
|
||||
"This cart does not support a real time clock."
|
||||
"\n"
|
||||
"Current date & time: %s\n"
|
||||
"\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown"
|
||||
);
|
||||
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n"
|
||||
"B: Back"
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_RIGHT, VALIGN_TOP,
|
||||
"Up/Down: Adjust Field\n"
|
||||
"Left/Right: Switch Field"
|
||||
);
|
||||
component_actions_bar_text_draw(
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"R: Save\n"
|
||||
"B: Back"
|
||||
);
|
||||
}
|
||||
|
||||
if (is_editing_mode) {
|
||||
component_editdatetime_draw(rtc_tm, editing_field_type);
|
||||
}
|
||||
|
||||
rdpq_detach_show();
|
||||
}
|
||||
|
||||
|
||||
void view_rtc_init (menu_t *menu) {
|
||||
// Nothing to initialize (yet)
|
||||
is_editing_mode = false;
|
||||
editing_field_type = RTC_EDIT_YEAR;
|
||||
}
|
||||
|
||||
void view_rtc_display (menu_t *menu, surface_t *display) {
|
||||
|
@ -136,6 +136,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
ALIGN_LEFT, VALIGN_TOP,
|
||||
"\n\n"
|
||||
" Default Directory : %s\n\n"
|
||||
" Autoload ROM : %s\n"
|
||||
"To change the following menu settings, press 'A':\n"
|
||||
"* PAL60 Mode : %s\n"
|
||||
" Show Hidden Files : %s\n"
|
||||
@ -149,6 +150,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"Note: Certain settings have the following caveats:\n"
|
||||
"* Requires rebooting the N64 Console.\n",
|
||||
menu->settings.default_directory,
|
||||
format_switch(menu->settings.rom_autoload_enabled),
|
||||
format_switch(menu->settings.pal60_enabled),
|
||||
format_switch(menu->settings.show_protected_entries),
|
||||
format_switch(menu->settings.use_saves_folder),
|
||||
|
@ -9,6 +9,27 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
|
||||
|
||||
void view_startup_init (menu_t *menu) {
|
||||
// FIXME: rather than use a controller button, would it be better to use the cart button?
|
||||
JOYPAD_PORT_FOREACH (port) {
|
||||
joypad_poll();
|
||||
joypad_buttons_t b_held = joypad_get_buttons_held(port);
|
||||
|
||||
if (menu->settings.rom_autoload_enabled && b_held.start) {
|
||||
menu->settings.rom_autoload_enabled = false;
|
||||
menu->settings.rom_autoload_path = "";
|
||||
menu->settings.rom_autoload_filename = "";
|
||||
settings_save(&menu->settings);
|
||||
}
|
||||
}
|
||||
if (menu->settings.rom_autoload_enabled) {
|
||||
menu->browser.directory = path_init(menu->storage_prefix, menu->settings.rom_autoload_path);
|
||||
menu->load.rom_path = path_clone_push(menu->browser.directory, menu->settings.rom_autoload_filename);
|
||||
menu->boot_pending.rom_file = true;
|
||||
menu->next_mode = MENU_MODE_LOAD_ROM;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
menu->next_mode = MENU_MODE_BROWSER;
|
||||
}
|
||||
|
||||
|
@ -57,7 +57,7 @@ static void draw (menu_t *menu, surface_t *d) {
|
||||
"Joypad 2 is %sconnected %s\n"
|
||||
"Joypad 3 is %sconnected %s\n"
|
||||
"Joypad 4 is %sconnected %s\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown\n",
|
||||
menu->current_time >= 0 ? ctime(&menu->current_time) : "Unknown",
|
||||
is_memory_expanded() ? "" : "not ",
|
||||
(joypad[0]) ? "" : "not ", format_accessory(0),
|
||||
(joypad[1]) ? "" : "not ", format_accessory(1),
|
||||
|
Loading…
Reference in New Issue
Block a user