Merge branch 'develop' into cpak-management

This commit is contained in:
Robin Jones 2024-11-07 20:33:52 +00:00 committed by GitHub
commit 2c10eb55b1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 808 additions and 227 deletions

View File

@ -74,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.

@ -1 +1 @@
Subproject commit e93802aec7e7839710281824ce2e9e4689b3a01d
Subproject commit 5295016230d657cd6c7fce5b6ed4a342538e09f5

View File

@ -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__ */

View File

@ -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__ */

View File

@ -1,4 +1,4 @@
## 64drive developer notes
# 64drive developer notes
### Official documentation

View File

@ -1,4 +1,4 @@
## SummerCart64 developer notes
# SummerCart64 developer notes
### Official documentation

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -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__ */

View File

@ -169,6 +169,7 @@ void view_load_disk_init (menu_t *menu) {
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);

View File

@ -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( &timestamp );
}
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) {
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,51 @@ static void draw (menu_t *menu, surface_t *d) {
component_layout_draw();
component_main_text_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"
);
component_main_text_draw(
ALIGN_LEFT, VALIGN_TOP,
"\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"
);
if (!is_editing_mode) {
component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP,
"A: Change\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"
);
}
component_actions_bar_text_draw(
ALIGN_LEFT, VALIGN_TOP,
"\n" // "A: 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) {

View File

@ -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),