Menu improvements (#9)

<!--- Provide a general summary of your changes in the Title above -->

## Description
<!--- Describe your changes in detail -->
This PR adds docfx to the CI to target documentation for the
N64FlashcartMenu and updates the libdragon submodule.
It also adds a number of menu improvements.

## Motivation and Context
<!--- What does this sample do? What problem does it solve? -->
<!--- If it fixes/closes/resolves an open issue, please link to the
issue here -->
Will eventually stop us from being lazy, however as the project is very
much WiP,
Currently the CI only runs it to show what warnings need to be "fixed".
In future, it needs to "error" when things are incorrect AND deploy to
the WIKI.


## How Has This Been Tested?
<!-- (if applicable) -->
<!--- Please describe in detail how you tested your sample/changes. -->
<!--- Include details of your testing environment, and the tests you ran
to -->
<!--- see how your change affects other areas of the code, etc. -->
Builds on my fork.

## Screenshots
<!-- (if appropriate): -->

![image](https://github.com/Polprzewodnikowy/N64FlashcartMenu/assets/11439699/04511e4a-e522-4b69-a8cb-59057c1c66aa)


## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all
the boxes that apply: -->
- [ ] Improvement (non-breaking change that adds a new feature)
- [ ] Bug fix (fixes an issue)
- [ ] Breaking change (breaking change)
- [x] Config and build (change in the configuration and build system,
has no impact on code or features)

## Checklist:
<!--- Go over all the following points, and put an `x` in all the boxes
that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're
here to help! -->
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.

<!--- It would be nice if you could sign off your contribution by
replacing the name with your GitHub user name and GitHub email contact.
-->
Signed-off-by: GITHUB_USER <GITHUB_USER_EMAIL>

---------

Co-authored-by: Mateusz Faderewski <sc@mateuszfaderewski.pl>
This commit is contained in:
Robin Jones 2023-07-08 23:52:39 +01:00 committed by GitHub
parent b53bbf7dae
commit b3509f4295
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 3138 additions and 108 deletions

View File

@ -2,7 +2,7 @@ FROM debian:bookworm-slim
RUN apt-get update && \
apt-get upgrade -y && \
apt-get install build-essential git python3 wget -y && \
apt-get install build-essential doxygen git python3 wget -y && \
wget https://github.com/DragonMinded/libdragon/releases/download/toolchain-continuous-prerelease/gcc-toolchain-mips64-x86_64.deb && \
dpkg -i gcc-toolchain-mips64-x86_64.deb && \
rm gcc-toolchain-mips64-x86_64.deb && \

View File

@ -1,4 +1,4 @@
name: build
name: Build
on:
push:
@ -9,14 +9,11 @@ on:
workflow_dispatch:
jobs:
build:
build-sc64-menu:
runs-on: ubuntu-latest
steps:
# - name: Check for dockerenv file
# run: (ls /.dockerenv && echo Found dockerenv) || (echo No dockerenv)
- uses: actions/checkout@v3
with:
submodules: recursive
@ -49,7 +46,7 @@ jobs:
minify-sc64-menu:
runs-on: ubuntu-latest
needs: build
needs: build-sc64-menu
steps:
@ -69,7 +66,7 @@ jobs:
name: N64FlashcartMenu
path: ./
- name: Finalize rom
- name: Finalize ROM
run: |
# make all
python ./tools/sc64/minify.py ./build/N64FlashcartMenu.elf ./output/N64FlashcartMenu.z64 ./output/sc64menu.n64
@ -83,6 +80,28 @@ jobs:
./output/sc64menu.n64
if-no-files-found: ignore
generate-docs:
runs-on: ubuntu-latest
# needs: build-sc64-menu
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
fetch-depth: 1 # we only require the last check-in, unless we want to create a changelog.
- name: Run Doxygen
uses: mattnotmitt/doxygen-action@1.9.5
with:
doxyfile-path: './Doxyfile'
# - name: Deploy
# uses: peaceiris/actions-gh-pages@v3
# with:
# github_token: ${{ secrets.GITHUB_TOKEN }}
# publish_dir: ./docs
# release-sc64-menu:
# runs-on: ubuntu-latest

1
.gitignore vendored
View File

@ -1,6 +1,7 @@
/.vscode
/build
/output
/docs
tools/sc64/sc64.exe
tools/sc64/sc64deployer.exe
# There should never be ROMs uploaded, but just incase, make sure they are excluded.

2688
Doxyfile Normal file

File diff suppressed because it is too large Load Diff

View File

@ -37,6 +37,7 @@ SRCS = \
menu/views/load.c \
menu/views/player.c \
menu/views/startup.c \
menu/views/system_info.c \
utils/fs.c
ASSETS = \
@ -70,12 +71,16 @@ clean:
$(shell rm -rf ./$(BUILD_DIR) ./$(OUTPUT_DIR))
.PHONY: clean
# run:
# $(shell ./remotedeploy.sh -d)
run: $(PROJECT_NAME)
./remotedeploy.sh
# FIXME: improve ability to deploy.
# if devcontainer, use remotedeploy.sh, else
# $(shell sc64deployer --boot direct-rom %~dp0$(OUTPUT_DIR))\$(PROJECT_NAME).z64)
# .PHONY: run
.PHONY: run
run-debug: $(PROJECT_NAME)
./remotedeploy.sh -d
.PHONY: run-debug
# test:
# TODO: run tests

View File

@ -62,11 +62,11 @@ You can use a dev container in VSCode to ease development.
## To deploy:
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.15.1/sc64-deployer-windows-v2.15.1.zip)
* Download the deployer [here](https://github.com/Polprzewodnikowy/SummerCart64/releases/download/v2.16.0/sc64-deployer-windows-v2.16.0.zip)
* Extract and place `sc64deployer.exe` in the `tools/sc64` directory.
Make sure that your firmware is compatible (currently v2.15.1+)
See: https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.15.1/docs/00_quick_startup_guide.md#firmware-backupupdate
Make sure that your firmware is compatible (currently v2.16.0+)
See: https://github.com/Polprzewodnikowy/SummerCart64/blob/v2.16.0/docs/00_quick_startup_guide.md#firmware-backupupdate
@ -92,6 +92,10 @@ The ROM can be found in the `output` directory.
NOTE: a "release" version of the SC64 menu is called `sc64menu.n64` and can be created for when you want to add it directly to the SDCard. This is generated by running `make all` or running `make sc64_minify`.
# Update Libdragon
# Update Libdragon submodule
This repo currently uses the `unstable` branch as a submodule at a specific commit.
To update to the latest version, use `git submodule update --remote ` from the terminal.
# Generate documentation
Run `doxygen` from the dev container terminal.
Make sure you fix the warnings before creating a PR!

0
assets/images/.gitkeep Normal file
View File

View File

@ -5,6 +5,7 @@
#define ACTIONS_REPEAT_DELAY 16
#define ACTIONS_REPEAT_RATE 2
#define JOYSTICK_DEADZONE 32
static void actions_clear (menu_t *menu) {
@ -15,7 +16,8 @@ static void actions_clear (menu_t *menu) {
menu->actions.fast = false;
menu->actions.enter = false;
menu->actions.back = false;
menu->actions.info = false;
menu->actions.file_info = false;
menu->actions.system_info = false;
menu->actions.settings = false;
menu->actions.override = false;
}
@ -26,6 +28,7 @@ void actions_update (menu_t *menu) {
struct controller_data down = get_keys_down();
struct controller_data held = get_keys_held();
struct controller_data pressed = get_keys_pressed();
if (down.c[0].err != ERROR_NONE) {
return;
@ -61,6 +64,22 @@ void actions_update (menu_t *menu) {
menu->actions.fast = true;
}
}
} else if (pressed.c[0].y > +JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) {
menu->actions.go_up = true;
if (pressed.c[0].y < +75) {
menu->actions.vertical_held_counter = 0;
}
}
} else if (pressed.c[0].y < -JOYSTICK_DEADZONE) { // TODO: requires improvement for responsiveness
menu->actions.vertical_held_counter += 1;
if ((menu->actions.vertical_held_counter >= ACTIONS_REPEAT_DELAY / 2) && (menu->actions.vertical_held_counter % ACTIONS_REPEAT_RATE)) {
menu->actions.go_down = true;
if (pressed.c[0].y > -75) {
menu->actions.vertical_held_counter = 0;
}
}
}
if (down.c[0].left) {
@ -85,9 +104,11 @@ void actions_update (menu_t *menu) {
menu->actions.enter = true;
} else if (down.c[0].B) {
menu->actions.back = true;
} else if (down.c[0].Z) {
menu->actions.info = true;
} else if (down.c[0].R) {
menu->actions.file_info = true;
} else if (down.c[0].L) {
menu->actions.system_info = true;
} else if (down.c[0].start) {
menu->actions.settings = true;
}

View File

@ -16,6 +16,8 @@ static bool boot_pending;
static void menu_init (settings_t *settings) {
controller_init();
timer_init();
rtc_init();
audio_init(44100, 2);
mixer_init(2);
display_init(RESOLUTION_640x480, DEPTH_16_BPP, 2, GAMMA_NONE, ANTIALIAS_OFF);
@ -53,6 +55,8 @@ static void menu_deinit (menu_t *menu) {
display_close();
mixer_close();
audio_close();
rtc_close();
timer_close();
}
@ -80,6 +84,10 @@ void menu_run (settings_t *settings) {
view_file_info_display(menu, display);
break;
case MENU_MODE_SYSTEM_INFO:
view_system_info_display(menu, display);
break;
case MENU_MODE_PLAYER:
view_player_display(menu, display);
break;
@ -118,6 +126,10 @@ void menu_run (settings_t *settings) {
view_file_info_init(menu);
break;
case MENU_MODE_SYSTEM_INFO:
view_system_info_init(menu);
break;
case MENU_MODE_PLAYER:
view_player_init(menu);
break;

View File

@ -15,6 +15,7 @@ typedef enum {
MENU_MODE_STARTUP,
MENU_MODE_BROWSER,
MENU_MODE_FILE_INFO,
MENU_MODE_SYSTEM_INFO,
MENU_MODE_PLAYER,
MENU_MODE_CREDITS,
MENU_MODE_LOAD,
@ -56,7 +57,8 @@ typedef struct {
bool enter;
bool back;
bool info;
bool file_info;
bool system_info;
bool settings;
bool override;
} actions;

View File

@ -11,22 +11,22 @@ uint8_t extract_homebrew_setting(uint8_t setting, uint8_t bit_position) {
uint8_t extract_homebrew_save_type(uint8_t save_type) {
switch (save_type) {
case 0x00:
case HB_SAVE_TYPE_NONE:
return DB_SAVE_TYPE_NONE;
case 0x01:
case HB_SAVE_TYPE_EEPROM_4K:
return DB_SAVE_TYPE_EEPROM_4K;
case 0x02:
case HB_SAVE_TYPE_EEPROM_16K:
return DB_SAVE_TYPE_EEPROM_16K;
case 0x03:
case HB_SAVE_TYPE_SRAM:
return DB_SAVE_TYPE_SRAM;
case 0x04:
case HB_SAVE_TYPE_SRAM_BANKED:
return DB_SAVE_TYPE_SRAM_BANKED;
case 0x05:
case HB_SAVE_TYPE_FLASHRAM:
return DB_SAVE_TYPE_FLASHRAM;
case 0x06:
case HB_SAVE_TYPE_SRAM_128K:
return DB_SAVE_TYPE_SRAM_128K;
default:
return DB_SAVE_TYPE_CART_SPECIFIED; // Invalid save type, handle accordingly
return DB_SAVE_TYPE_INVALID; // Invalid save type, handle accordingly
}
}
@ -43,11 +43,13 @@ rom_header_t file_read_rom_header(char *path) {
rom_header_t *rom_header = malloc(sizeof(rom_header_t));
fseek(fp, 0x00, SEEK_SET);
fread(&(rom_header->endian), sizeof(uint32_t), 1, fp);
// FIXME: handle endian appropriately, perhaps: cart_card_byteswap
fseek(fp, 0x10, SEEK_SET);
fread(&(rom_header->checksum), sizeof(uint64_t), 1, fp);
fseek(fp, 0x20, SEEK_SET);
fread(&(rom_header->title), sizeof(rom_header->title), 1, fp);
rom_header->title[20] = '\0';
fgets(rom_header->title, sizeof(rom_header->title), fp);
fseek(fp, 0x3b, SEEK_SET);
fread(&(rom_header->metadata.media_type), sizeof(rom_header->metadata.media_type), 1, fp);
//fseek(fp, 0x3c, SEEK_SET); // Consecutive read (no need to seek).
@ -70,28 +72,28 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
// These are ordered to ensure they are handled correctly...
// First: Match by the `ED` Developer ID
// TODO: if appropriate this can be improved with other unused codes... e.g. | `AA` | `ZZ`
if (rom_header.metadata.unique_identifier == *(uint16_t *)"ED") {
// First: Match by the `ED` or `HB` Developer ID
if (rom_header.metadata.unique_identifier == *(uint16_t *)"ED" || rom_header.metadata.unique_identifier == *(uint16_t *)"HB") {
// #ifdef ED64_COMPATIBLE
// uint8_t low_nibble = rom_header.version & 0x0F;
// uint8_t rtc_enabled = extract_homebrew_setting(low_nibble, 0); // Bit 0
// uint8_t region_free_enabled = extract_homebrew_setting(low_nibble, 1); // Bit 1
// #endif
uint8_t high_nibble = (rom_header.version >> 4) & 0x0F;
return extract_homebrew_save_type(high_nibble);
}
// // Second: Match the default entries for crc_high.
// // FIXME: use full check code, or pad.
// if (rom_header.checksum == 0xbcb1f89f)return DB_SAVE_TYPE_EEPROM_4K; // kirby v1.3
// if (rom_header.checksum == 0x46039fb4)return DB_SAVE_TYPE_EEPROM_16K; // kirby U
// if (rom_header.checksum == 0x0d93ba11)return DB_SAVE_TYPE_EEPROM_16K; // kirby U
// if (rom_header.checksum == 0xce84793d)return DB_SAVE_TYPE_SRAM; // donkey kong f2
// if (rom_header.checksum == 0x4cbc3b56)return DB_SAVE_TYPE_SRAM; // DMTJ 64DD game
// if (rom_header.checksum == 0x0dd4abab)return DB_SAVE_TYPE_EEPROM_16K; // DK Retail kiosk demo (shares ID with Dinosaur planet, but hacks are unlikely)!
// if (rom_header.checksum == 0xeb85ebc9)return DB_SAVE_TYPE_FLASHRAM; // DOUBUTSU BANCHOU (ANIMAL LEADER, Cubivore) - Contains no game ID
// Second: Match the default entries for crc.
// DOUBUTSU BANCHOU (ANIMAL LEADER, Cubivore) - Contains no game ID
if (rom_header.checksum == 16971230020836426415U) return DB_SAVE_TYPE_FLASHRAM;
// DK Retail kiosk demo (shares ID with Dinosaur planet, but hacks are unlikely)!
if (rom_header.checksum == 996610171530815774U) return DB_SAVE_TYPE_EEPROM_16K;
// donkey kong f2
// if (rom_header.checksum == 0xce84793d) return DB_SAVE_TYPE_SRAM;
// DMTJ 64DD game
// if (rom_header.checksum == 0x4cbc3b56) return DB_SAVE_TYPE_SRAM;
// FIXME: we need to take into account the Category (first char) and the Region code (last char) before a general match of the ID.
@ -119,6 +121,10 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
// FLASHRAM
"AF", "CC", "CK", "DL", "DP", "JD", "JF", "KJ", "M6", "MQ", "P2", "P3", "PF", "PH", "PN", "PO",
"PS", "RH", "SI", "SQ", "T9", "W4", "ZS",
// Controller Pak only
"BX", "BQ", "NS",
// Last entry
"!!"
@ -144,6 +150,10 @@ uint8_t rom_db_match_save_type(rom_header_t rom_header) {
// FLASHRAM
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
// Controller Pak only
0x10, 0x10, 0x10,
// Last entry.
0xff
};

View File

@ -12,8 +12,26 @@
#define DB_SAVE_TYPE_SRAM_BANKED 0x04
#define DB_SAVE_TYPE_SRAM_128K 0x05
#define DB_SAVE_TYPE_FLASHRAM 0x06
#define DB_SAVE_TYPE_CART_SPECIFIED 0xff
#define DB_SAVE_TYPE_CPAK 0x10
#define DB_SAVE_TYPE_DD 0x20
#define DB_SAVE_TYPE_INVALID 0xff
typedef enum {
HB_SAVE_TYPE_NONE = 0x00,
HB_SAVE_TYPE_EEPROM_4K = 0x01,
HB_SAVE_TYPE_EEPROM_16K = 0x02,
HB_SAVE_TYPE_SRAM = 0x03,
HB_SAVE_TYPE_SRAM_BANKED = 0x04,
HB_SAVE_TYPE_FLASHRAM = 0x05,
HB_SAVE_TYPE_SRAM_128K = 0x06,
} homebrew_savetype_t;
typedef enum {
ROM_BIG_ENDIAN = 2151092800U,
ROM_LITTLE_ENDIAN = 1074935680U,
ROM_MID_BIG_ENDIAN = 931151890U,
ROM_MID_LITTLE_ENDIAN = 306217015U
} rom_endian_type_t;
//Rom Info
// CheckCode 0x10, 8 bytes (sometimes refered to as CRC Hi and CRC Lo)
@ -24,44 +42,43 @@
// DestinationCode 0x3e
// RomVersion 0x3f
// typedef enum {
// N64_CART = 'N',
// N64_DISK = 'D',
// N64_CART_EXPANDABLE = 'C',
// N64_DISK_EXPANDABLE = 'E',
// N64_ALECK64 = 'Z',
// //TYPE_UNKNOWN = '\0'
// } rom_media_type_t;
typedef enum {
N64_CART = 'N',
N64_DISK = 'D',
N64_CART_EXPANDABLE = 'C',
N64_DISK_EXPANDABLE = 'E',
N64_ALECK64 = 'Z'
} rom_media_type_t;
// typedef enum {
// MARKET_ALL = 'A',
// MARKET_BRAZIL = 'B',
// MARKET_CHINA = 'C',
// MARKET_GERMANY = 'D',
// MARKET_USA = 'E',
// MARKET_FRANCE = 'F',
// MARKET_GATEWAY64_NTSC = 'G',
// MARKET_NETHERLANDS = 'H',
// MARKET_ITALY = 'I',
// MARKET_JAPAN = 'J',
// MARKET_KOREA = 'K',
// MARKET_GATEWAY64_PAL = 'L',
typedef enum {
MARKET_ALL = 'A',
MARKET_BRAZIL = 'B',
MARKET_CHINA = 'C',
MARKET_GERMANY = 'D',
MARKET_USA = 'E',
MARKET_FRANCE = 'F',
MARKET_GATEWAY64_NTSC = 'G',
MARKET_NETHERLANDS = 'H',
MARKET_ITALY = 'I',
MARKET_JAPAN = 'J',
MARKET_KOREA = 'K',
MARKET_GATEWAY64_PAL = 'L',
// MARKET_UNKNOWN_M = 'M',
// MARKET_CANADA = 'N',
MARKET_CANADA = 'N',
// MARKET_UNKNOWN_O = 'O',
// MARKET_EUROPE_P = 'P',
MARKET_EUROPE_P = 'P',
// MARKET_UNKNOWN_Q = 'Q',
// MARKET_UNKNOWN_R = 'R',
// MARKET_SPAIN = 'S',
MARKET_SPAIN = 'S',
// MARKET_UNKNOWN_T = 'T',
// MARKET_AUSTRAILA = 'U',
MARKET_AUSTRAILA = 'U',
// MARKET_UNKNOWN_V = 'V',
// MARKET_SCANDINAVAIA = 'W',
// MARKET_EUROPE_X = 'X',
// MARKET_EUROPE_Y = 'Y',
// MARKET_EUROPE_Z = 'Z',
// //MARKET_UNKNOWN = '\0'
// } rom_destination_market_t;
MARKET_SCANDINAVAIA = 'W',
MARKET_EUROPE_X = 'X',
MARKET_EUROPE_Y = 'Y',
MARKET_EUROPE_Z = 'Z'
} rom_destination_market_t;
typedef struct {
uint8_t media_type; // rom_media_type_t
@ -70,8 +87,9 @@ typedef struct {
} rom_metadata_t;
typedef struct {
uint32_t endian; // rom_endian_type_t
uint64_t checksum;
uint8_t title[21];
char title[21]; // 20 chars + null
rom_metadata_t metadata;
uint8_t version;
} rom_header_t;

View File

@ -215,10 +215,12 @@ static void process (menu_t *menu) {
menu->browser.valid = false;
menu->next_mode = MENU_MODE_ERROR;
}
} else if (menu->actions.info) {
} else if (menu->actions.file_info) {
if (menu->browser.selected >= 0) {
menu->next_mode = MENU_MODE_FILE_INFO;
}
} else if (menu->actions.system_info) {
menu->next_mode = MENU_MODE_SYSTEM_INFO;
} else if (menu->actions.settings) {
menu->next_mode = MENU_MODE_CREDITS;
}

View File

@ -4,8 +4,9 @@
#include "../menu_res_setup.h"
#define MENU_VERSION "V0.0.0.3"
#ifndef MENU_VERSION
#define MENU_VERSION "0.0.0.4"
#endif
static void process (menu_t *menu) {
@ -22,17 +23,21 @@ static void draw (menu_t *menu, surface_t *d) {
int16_t vertical_position = 40;
graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Version:");
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, MENU_VERSION);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Menu Revision: V");
graphics_draw_text(d, horizontal_start_position + 16 * 8, vertical_position, MENU_VERSION);
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Authors:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "JonesAlmighty / NetworkFusion");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "korgeaux / Polprzewodnikowy");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Credits:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "N64Brew / libdragon contributors.");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "Github:");
// graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/SummerCart64");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/Polprzewodnikowy/N64FlashcartMenu");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/NetworkFusion/N64FlashcartMenu");
//graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, "https://github.com/dragonminded/libdragon");
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "OSS licenses used:");
graphics_draw_text(d, horizontal_indent,vertical_position += font_vertical_pixels, "UNLICENSE");

View File

@ -1,6 +1,7 @@
#include <libdragon.h>
#include "views.h"
#include "../menu_res_setup.h"
static void process (menu_t *menu) {
@ -12,7 +13,7 @@ static void process (menu_t *menu) {
static void draw (menu_t *menu, surface_t *d) {
graphics_fill_screen(d, graphics_make_color(0, 0, 0, 255));
graphics_draw_text(d, 24, 36, "ERROR!");
graphics_draw_text(d, overscan_horizontal_pixels, overscan_vertical_pixels, "ERROR!");
display_show(d);
}

View File

@ -5,35 +5,123 @@
#include "../menu_res_setup.h"
#include "../../utils/str_utils.h"
#include "../rom_database.h"
#include "fragments/fragments.h"
static FILINFO info;
static char *get_rom_endian_s (uint32_t endian) {
switch (endian)
{
case ROM_BIG_ENDIAN:
return "Big (default)"; // expected
break;
case ROM_LITTLE_ENDIAN:
return "Little";
break;
case ROM_MID_LITTLE_ENDIAN:
return "Middle Little";
break;
case ROM_MID_BIG_ENDIAN:
return "Middle Big";
break;
default:
return "Unknown";
break;
}
}
static char *get_file_type (void) {
static char *get_rom_mediatype_s (uint8_t type) {
switch (type)
{
case N64_CART:
return "N - Cartridge";
break;
case N64_DISK:
return "D - Disk";
break;
case N64_CART_EXPANDABLE:
return "C - Cart Expandable";
break;
case N64_DISK_EXPANDABLE:
return "E - Disk Expandable";
break;
case N64_ALECK64:
return "Z - Aleck64";
break;
default:
return "Unknown";
break;
}
}
static char *get_rom_savetype_s (uint8_t type) {
switch (type)
{
case DB_SAVE_TYPE_EEPROM_4K:
return "EEPROM 4K";
break;
case DB_SAVE_TYPE_EEPROM_16K:
return "EEPROM 16K";
break;
case DB_SAVE_TYPE_SRAM:
return "SRAM";
break;
case DB_SAVE_TYPE_SRAM_BANKED:
return "SRAM Banked";
break;
case DB_SAVE_TYPE_SRAM_128K:
return "SRAM 128K [ED64]";
break;
case DB_SAVE_TYPE_FLASHRAM:
return "FLASH RAM";
break;
case DB_SAVE_TYPE_CPAK:
return "Controller PAK";
break;
default:
return "Unknown";
break;
}
}
static char *get_file_type_s (void) {
// TODO: should be at least a switch statement!
if (str_endswith(info.fname, ".z64") || str_endswith(info.fname, ".n64") || str_endswith(info.fname, ".v64") || str_endswith(info.fname, ".rom")) {
if (str_endswith(info.fname, ".z64", false) ||
str_endswith(info.fname, ".n64", false) ||
str_endswith(info.fname, ".v64", false) ||
str_endswith(info.fname, ".rom", false)
) {
// TODO: check the necessary bytes in the header to ensure!
return "N64 ROM";
}
else if (str_endswith(info.fname, ".txt")) {
else if (str_endswith(info.fname, ".txt", false)) {
return "Text File";
}
else if (str_endswith(info.fname, ".ini")) {
else if (str_endswith(info.fname, ".ini", false)) {
return "INI File";
}
else if (str_endswith(info.fname, ".yml") || str_endswith(info.fname, ".yaml")) {
else if (str_endswith(info.fname, ".yml", false) || str_endswith(info.fname, ".yaml", false)) {
return "YAML File";
}
else if (str_endswith(info.fname, ".toml")) {
else if (str_endswith(info.fname, ".toml", false)) {
return "TOML File";
}
else if (str_endswith(info.fname, ".sav")) {
return "Save File";
else if (str_endswith(info.fname, ".sav", false) || str_endswith(info.fname, ".eep", false) || str_endswith(info.fname, ".sra", false) || str_endswith(info.fname, ".srm", false)|| str_endswith(info.fname, ".fla", false)) {
return "ROM Save File";
}
else if (str_endswith(info.fname, ".emu")) {
else if (str_endswith(info.fname, ".ips", false) || str_endswith(info.fname, ".aps", false) || str_endswith(info.fname, ".pps", false) || str_endswith(info.fname, ".xdelta", false)) {
return "ROM Patch File";
}
else if (str_endswith(info.fname, ".zip", false)) {
return "ZIP Archive";
}
else if (str_endswith(info.fname, ".mpk", false)) {
return "DexDrive CPak Backup File";
}
else if (str_endswith(info.fname, ".emu", false)) {
return "Emulator File";
}
else {
@ -92,9 +180,43 @@ static void draw (menu_t *menu, surface_t *d) {
vertical_position += (font_vertical_pixels * 2);
graphics_draw_text(d, horizontal_start_position, vertical_position, "Type:");
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type());
graphics_draw_text(d, horizontal_indent, vertical_position += font_vertical_pixels, get_file_type_s());
// TODO: split into a seperate menu item.
if (strcmp(get_file_type_s(), "N64 ROM") == 0) {
graphics_draw_line(d, d->width / 2, 67, d->width / 2, d->height - 45, 0xff);
int x_start_position = (d->width / 2) + horizontal_start_position;
int y_position = 67;
graphics_draw_text(d, x_start_position, y_position, "N64 ROM Information:\n\n");
y_position += (font_vertical_pixels * 2);
path_t *path = path_clone(menu->browser.directory);
path_push(path, menu->browser.list[menu->browser.selected].name);
rom_header_t temp_header = file_read_rom_header(path_get(path));
sprintf(str_buffer,"File Endian: %s\n", get_rom_endian_s(temp_header.endian));
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
y_position += (font_vertical_pixels * 2);
sprintf(str_buffer,"Title: %s\n", temp_header.title);
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer,"Media Type: %s\n", get_rom_mediatype_s(temp_header.metadata.media_type));
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer,"Unique ID: %.2s\n", (char*)&(temp_header.metadata.unique_identifier));
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer,"Destination Market: %c\n", temp_header.metadata.destination_market);
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer,"Version: %hhu\n", temp_header.version);
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer,"Checksum: %llu\n", temp_header.checksum);
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
y_position += (font_vertical_pixels * 2);
uint8_t save_type = rom_db_match_save_type(temp_header);
sprintf(str_buffer,"Save Type: %s\n", get_rom_savetype_s(save_type));
graphics_draw_text(d, x_start_position, y_position += font_vertical_pixels, str_buffer);
//menu_fileinfo_draw_n64_rom_info(d);
}
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2

View File

@ -21,7 +21,7 @@ static void load (menu_t *menu) {
uint8_t save_type = rom_db_match_save_type(temp_header);
if (flashcart_load_rom(path_get(path), false) != FLASHCART_OK) {
if (flashcart_load_rom(path_get(path), temp_header.endian == ROM_MID_BIG_ENDIAN) != FLASHCART_OK) {
menu->next_mode = MENU_MODE_ERROR;
path_free(path);
return;
@ -57,6 +57,8 @@ static void draw (menu_t *menu, surface_t *d) {
// Layout
fragment_borders(d);
// TODO: Display ROM information here
rdpq_detach_show();
}

View File

@ -0,0 +1,97 @@
#include <time.h>
#include <libdragon.h>
#include "views.h"
#include "../menu_res_setup.h"
char *accessory_type_s( int accessory )
{
switch( accessory )
{
case ACCESSORY_RUMBLEPAK:
return "[RumblePak]";
case ACCESSORY_MEMPAK:
return "[ControllerPak]";
case ACCESSORY_VRU:
return "[VRU]";
case ACCESSORY_TRANSFERPAK:
return "[TransferPak]";
default:
return "Unknown";
}
}
static void process (menu_t *menu) {
if (menu->actions.back) {
menu->next_mode = MENU_MODE_BROWSER;
}
}
static void draw (menu_t *menu, surface_t *d) {
char str_buffer[512];
graphics_fill_screen(d, 0x00);
graphics_draw_text(d, (d->width / 2) - 64, vertical_start_position, "N64 SYSTEM INFORMATION"); // centre = numchars * font_horizontal_pixels / 2
graphics_draw_line(d, 0, 30, d->width, 30, 0xff);
int16_t vertical_position = 40;
time_t current_time = -1;
current_time = time( NULL );
if( current_time != -1 )
{
sprintf(str_buffer, "Current date & time: %s\n\n", ctime( &current_time ));
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, "To change the time, use USB App...");
}
vertical_position += font_vertical_pixels;
int controllers = get_controllers_present();
sprintf(str_buffer, "JoyPad 1 is %sconnected\n", (controllers & CONTROLLER_1_INSERTED) ? "" : "not " );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 2 is %sconnected\n", (controllers & CONTROLLER_2_INSERTED) ? "" : "not " );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 3 is %sconnected\n", (controllers & CONTROLLER_3_INSERTED) ? "" : "not " );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 4 is %sconnected\n", (controllers & CONTROLLER_4_INSERTED) ? "" : "not " );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
vertical_position += font_vertical_pixels;
struct controller_data output;
int accessories = get_accessories_present( &output );
sprintf(str_buffer, "JoyPad 1 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_1_INSERTED) ? "" : "not ",
(accessories & CONTROLLER_1_INSERTED) ? accessory_type_s( identify_accessory( 0 ) ) : "" );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 2 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_2_INSERTED) ? "" : "not ",
(accessories & CONTROLLER_2_INSERTED) ? accessory_type_s( identify_accessory( 1 ) ) : "" );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 3 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_3_INSERTED) ? "" : "not ",
(accessories & CONTROLLER_3_INSERTED) ? accessory_type_s( identify_accessory( 2 ) ) : "" );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
sprintf(str_buffer, "JoyPad 4 Accessory Pak is %sinserted %s\n", (accessories & CONTROLLER_4_INSERTED) ? "" : "not ",
(accessories & CONTROLLER_4_INSERTED) ? accessory_type_s( identify_accessory( 3 ) ) : "" );
graphics_draw_text(d, horizontal_start_position, vertical_position += font_vertical_pixels, str_buffer);
graphics_draw_line(d, 0, d->height - overscan_vertical_pixels - font_vertical_pixels, d->width,d->height - overscan_vertical_pixels - font_vertical_pixels, 0xff);
graphics_draw_text(d, (d->width / 2) - 80,d->height - overscan_vertical_pixels, "Press (B) to return!"); // centre = numchars * font_horizontal_pixels / 2
display_show(d);
}
void view_system_info_init (menu_t *menu) {
// Nothing to initialize (yet)
}
void view_system_info_display (menu_t *menu, surface_t *display) {
process(menu);
draw(menu, display);
}

View File

@ -13,6 +13,9 @@ void view_startup_display (menu_t *menu, surface_t *display);
void view_browser_init (menu_t *menu);
void view_browser_display (menu_t *menu, surface_t *display);
void view_system_info_init (menu_t *menu);
void view_system_info_display (menu_t *menu, surface_t *display);
void view_file_info_init (menu_t *menu);
void view_file_info_display (menu_t *menu, surface_t *display);

View File

@ -3,13 +3,31 @@
#include <stdio.h>
//#include <stdlib.h> // TODO: does this work... will unlock qsort!
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
// e.g. if (str_endswith(cur_rom, ".z64") || str_endswith(cur_rom, ".n64"))
static bool str_endswith(const char *str, const char *suffix) {
char *p = strstr(str, suffix);
return p && p[strlen(suffix)] == '\0';
// e.g. if (str_endswith(cur_rom, ".z64", false) || str_endswith(cur_rom, ".n64", false))
static bool str_endswith(const char *str, const char *suffix, bool case_sensitive) {
size_t str_len = strlen(str);
size_t suffix_len = strlen(suffix);
if (str_len < suffix_len)
return false;
if (!case_sensitive) {
for (size_t i = 0; i < suffix_len; i++) {
if (tolower(str[str_len - suffix_len + i]) != tolower(suffix[i]))
return false;
}
} else {
for (size_t i = 0; i < suffix_len; i++) {
if (str[str_len - suffix_len + i] != suffix[i])
return false;
}
}
return true;
}
#endif