mirror of
https://github.com/parasyte/alt64
synced 2024-12-12 02:32:16 -05:00
4660 lines
138 KiB
C
4660 lines
138 KiB
C
/*
|
|
* ALT64 Menu v0.1.8.6 - 2013
|
|
* a menu for the Everdrive64
|
|
* based on libdragon, Neo64Menu, ED64IO, libn64-hkz, libmikmod
|
|
* by saturnu
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
//libdragon n64 lib
|
|
#include <libdragon.h>
|
|
|
|
//everdrive system libs
|
|
#include "types.h"
|
|
#include "sys.h"
|
|
#include "everdrive.h"
|
|
#include "everdrive.h"
|
|
|
|
//filesystem
|
|
#include "disk.h"
|
|
#include "fat.h"
|
|
|
|
//utils
|
|
#include "utils.h"
|
|
|
|
//config file on sd
|
|
#include "ini.h"
|
|
#include "strlib.h"
|
|
|
|
//menu header
|
|
#include "menu.h"
|
|
|
|
//sound
|
|
#include <mikmod.h>
|
|
#include "mp3.h"
|
|
|
|
//cheats
|
|
struct gscEntry {
|
|
char *description;
|
|
char *gscodes;
|
|
u16 count;
|
|
u16 state;
|
|
u16 mask;
|
|
u16 value;
|
|
};
|
|
typedef struct gscEntry gscEntry_t;
|
|
|
|
gscEntry_t gGSCodes[256];
|
|
|
|
#ifdef USE_TRUETYPE
|
|
#define STB_TRUETYPE_IMPLEMENTATION
|
|
#include "stb_truetype.h"
|
|
|
|
struct glyph {
|
|
int xoff;
|
|
int yoff;
|
|
int adv;
|
|
int lsb;
|
|
float scale;
|
|
unsigned int color;
|
|
unsigned char *alpha;
|
|
sprite_t sprite;
|
|
};
|
|
typedef struct glyph glyph_t;
|
|
|
|
glyph_t sans[96];
|
|
glyph_t serif[96];
|
|
#endif
|
|
|
|
|
|
typedef struct
|
|
{
|
|
uint32_t type;
|
|
uint32_t color;
|
|
char filename[MAX_FILENAME_LEN+1];
|
|
} direntry_t;
|
|
|
|
|
|
//ini file
|
|
typedef struct
|
|
{
|
|
int version;
|
|
const char* name;
|
|
char* background_image;
|
|
char* border_color_1;
|
|
char* border_color_2;
|
|
char* box_color;
|
|
char* selection_color;
|
|
char* list_font_color;
|
|
char* list_dir_font_color;
|
|
char* selection_font_color;
|
|
char* mempak_path;
|
|
char* save_path;
|
|
int sound_on;
|
|
int page_display;
|
|
int tv_mode;
|
|
int quick_boot;
|
|
int enable_colored_list;
|
|
int ext_type;
|
|
int cd_behaviour;
|
|
int scroll_behaviour;
|
|
int text_offset;
|
|
int hide_sysfolder;
|
|
int sd_speed;
|
|
|
|
} configuration;
|
|
|
|
|
|
volatile u32 *romaddr_ptr = (u32 *) ROM_ADDR;
|
|
unsigned int gBootCic=CIC_6102;
|
|
u8 debug=DBG_MODE;
|
|
|
|
static uint8_t mempak_data[128 * 256];
|
|
static void *bg_buffer;
|
|
void *__safe_bg_buffer;
|
|
|
|
#define __get_buffer( x ) __safe_buffer[(x)-1]
|
|
extern uint32_t __bitdepth;
|
|
extern uint32_t __width;
|
|
extern uint32_t __height;
|
|
extern void *__safe_buffer[];
|
|
|
|
char firmware_str[64];
|
|
int firm_found=0;
|
|
char rom_config[10];
|
|
|
|
display_context_t lockVideo(int wait);
|
|
|
|
int select_mode = 0;
|
|
int toplist_reload=1;
|
|
int toplist_cursor=0;
|
|
char toplist15[15][256];
|
|
|
|
int fat_initialized=0;
|
|
int exit_ok = 0;
|
|
int boot_cic=0;
|
|
int boot_save=0;
|
|
int cursor_line=0;
|
|
int cursor_lastline=0;
|
|
u16 cursor_history[32];
|
|
u16 cursor_history_pos=0;
|
|
u8 empty=0;
|
|
u8 playing=0;
|
|
u8 gb_load_y=0;
|
|
|
|
//start with filebrowser menu key settings
|
|
int input_mapping=1;
|
|
/* 1=filemanager
|
|
* 2=mempak-menu
|
|
* 3=charinput
|
|
* 4=rom loaded
|
|
* 5=format mpk
|
|
* 6=restore mpk
|
|
* 7=rom config box
|
|
* 8=toplist
|
|
* 9=mpk choice
|
|
* 10=mpk quick-backup
|
|
* 11=mp3
|
|
* 98= A/B abort screen
|
|
*/
|
|
|
|
//holds the string of the character input screen result
|
|
int text_input_on=0;
|
|
|
|
//char input vars
|
|
int x,y,position,set;
|
|
|
|
unsigned char input_text[32];
|
|
uint32_t chr_forecolor;
|
|
uint32_t chr_backcolor;
|
|
|
|
//save type still set - save todo after reboot
|
|
int save_reboot=0;
|
|
|
|
//cart id from rom header
|
|
unsigned char cartID[4];
|
|
char curr_dirname[64];
|
|
char pwd[64];
|
|
char rom_filename[128];
|
|
|
|
u32 rom_buff[128]; //rom buffer
|
|
u8 *rom_buff8; //rom buffer
|
|
|
|
u8 *firmware;
|
|
u8 gbload=0;
|
|
|
|
int cheats_on=0;
|
|
int checksum_fix_on=0;
|
|
short int gCheats = 0; /* 0 = off, 1 = select, 2 = all */
|
|
short int force_tv = 0;
|
|
short int boot_country=0;
|
|
|
|
static resolution_t res = RESOLUTION_320x240;
|
|
|
|
//background sprites
|
|
sprite_t *loadPng(u8 *png_filename);
|
|
sprite_t *background; //background
|
|
sprite_t *background0; //splash screen
|
|
|
|
//config file theme settings
|
|
u32 border_color_1=0xFFFFFFFF; //hex 0xRRGGBBAA AA=transparenxy
|
|
u32 border_color_2=0x3F3F3FFF;
|
|
u32 box_color=0x00000080;
|
|
u32 selection_color=0x6495ED60;
|
|
u32 selection_font_color=0xFFFFFFFF;
|
|
u32 list_font_color=0xFFFFFFFF;
|
|
u32 list_dir_font_color=0xFFFFFFFF;
|
|
|
|
char* border_color_1_s;
|
|
char* border_color_2_s;
|
|
char* box_color_s;
|
|
char* selection_color_s;
|
|
char* selection_font_color_s;
|
|
char* list_font_color_s;
|
|
char* list_dir_font_color_s;
|
|
|
|
char* mempak_path;
|
|
char* save_path;
|
|
|
|
u8 sound_on=0;
|
|
u8 page_display=0;
|
|
int text_offset=0;
|
|
u8 tv_mode=0; // 1=ntsc 2=pal 3=mpal 0=default automatic
|
|
u8 quick_boot=0;
|
|
u8 enable_colored_list=0;
|
|
u8 cd_behaviour=0; //0=first entry 1=last entry
|
|
u8 scroll_behaviour=0; //1=classic 0=new page-system
|
|
u8 ext_type=0; //0=classic 1=org os
|
|
u8 sd_speed=1; // 1=25Mhz 2=50Mhz
|
|
u8 hide_sysfolder=0;
|
|
char* background_image;
|
|
|
|
//toplist helper
|
|
int list_pos_backup[3];
|
|
char list_pwd_backup[256];
|
|
|
|
char dirz[512] = "rom://";
|
|
|
|
short int gCursorX;
|
|
short int gCursorY;
|
|
|
|
int count = 0;
|
|
int page = 0;
|
|
int cursor = 0;
|
|
direntry_t *list;
|
|
|
|
int filesize( FILE *pFile )
|
|
{
|
|
fseek( pFile, 0, SEEK_END );
|
|
int lSize = ftell( pFile );
|
|
rewind( pFile );
|
|
|
|
return lSize;
|
|
}
|
|
|
|
sprite_t *read_sprite( const char * const spritename ) {
|
|
FILE *fp = fopen( spritename, "r" );
|
|
|
|
if( fp ) {
|
|
sprite_t *sp = malloc( filesize( fp ) );
|
|
fread( sp, 1, filesize( fp ), fp );
|
|
fclose( fp );
|
|
|
|
return sp;
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
void drawSelection(display_context_t disp,int p){
|
|
int s_x=23+(text_offset*8);
|
|
|
|
if(scroll_behaviour){
|
|
if(select_mode){
|
|
if(cursor_lastline>cursor && cursor_line > 0) {
|
|
cursor_line--;
|
|
}
|
|
|
|
if(cursor_lastline<cursor && cursor_line < 19) {
|
|
cursor_line++;
|
|
}
|
|
|
|
p=cursor_line;
|
|
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color); //(p+3) diff
|
|
cursor_lastline=cursor;
|
|
}
|
|
}
|
|
else { //new page-system
|
|
//accept p
|
|
graphics_draw_box_trans(disp, s_x, (((p+3)*8)+24), 272, 8, selection_color);
|
|
}
|
|
}
|
|
|
|
void drawConfigSelection(display_context_t disp,int l){
|
|
int s_x=62+(text_offset*8);
|
|
|
|
l=l+5;
|
|
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 193, 8, 0x00000080); //(p+3) diff
|
|
}
|
|
|
|
void drawToplistSelection(display_context_t disp,int l){
|
|
int s_x=30+(text_offset*8);
|
|
|
|
l=l+2;
|
|
graphics_draw_box_trans(disp, s_x, (((l+3)*8)+24), 256, 8, 0xFFFFFF70); //(p+3) diff
|
|
}
|
|
|
|
|
|
|
|
void chdir( const char * const dirent ) {
|
|
/* Ghetto implementation */
|
|
if( strcmp( dirent, ".." ) == 0 ) {
|
|
/* Go up one */
|
|
int len = strlen( dirz ) - 1;
|
|
|
|
/* Stop going past the min */
|
|
if( dirz[len] == '/' && dirz[len-1] == '/' && dirz[len-2] == ':' ) {
|
|
//return if ://
|
|
return;
|
|
}
|
|
|
|
if( dirz[len] == '/' ) {
|
|
dirz[len] = 0;
|
|
len--;
|
|
}
|
|
|
|
while( dirz[len] != '/') {
|
|
dirz[len] = 0;
|
|
len--;
|
|
}
|
|
}
|
|
else {
|
|
/* Add to end */
|
|
strcat( dirz, dirent );
|
|
strcat( dirz, "/" );
|
|
}
|
|
}
|
|
|
|
|
|
int compare(const void * a, const void * b) {
|
|
direntry_t *first = (direntry_t *)a;
|
|
direntry_t *second = (direntry_t *)b;
|
|
|
|
if(first->type == DT_DIR && second->type != DT_DIR) {
|
|
/* First should be first */
|
|
return -1;
|
|
}
|
|
|
|
if(first->type != DT_DIR && second->type == DT_DIR) {
|
|
/* First should be second */
|
|
return 1;
|
|
}
|
|
|
|
return strcmp(first->filename, second->filename);
|
|
}
|
|
|
|
int compare_int (const void *a, const void *b) {
|
|
const int *ia = (const int *)a; // casting pointer types
|
|
const int *ib = (const int *)b;
|
|
return *ia - *ib;
|
|
}
|
|
|
|
int compare_int_reverse (const void *a, const void *b) {
|
|
const int *ia = (const int *)a; // casting pointer types
|
|
const int *ib = (const int *)b;
|
|
return *ib - *ia;
|
|
}
|
|
|
|
void free_dir(direntry_t *dirz) {
|
|
if(dirz) { free(dirz); }
|
|
}
|
|
|
|
void new_scroll_pos(int *cursor, int *page, int max, int count) {
|
|
/* Make sure windows too small can be calculated right */
|
|
if(max > count) {
|
|
max = count;
|
|
}
|
|
|
|
/* Bounds checking */
|
|
if(*cursor >= count) {
|
|
*cursor = count-1;
|
|
}
|
|
|
|
if(*cursor < 0) {
|
|
*cursor = 0;
|
|
}
|
|
|
|
/* Scrolled up? */
|
|
if(*cursor < *page) {
|
|
*page = *cursor;
|
|
return;
|
|
}
|
|
|
|
/* Scrolled down/ */
|
|
if(*cursor >= (*page + max)) {
|
|
*page = (*cursor - max) + 1;
|
|
return;
|
|
}
|
|
|
|
/* Nothing here, should be good! */
|
|
}
|
|
|
|
void display_dir(direntry_t *list, int cursor, int page, int max, int count, display_context_t disp) {
|
|
//system color
|
|
uint32_t forecolor=0;
|
|
uint32_t forecolor_menu=0;
|
|
uint32_t backcolor;
|
|
backcolor = graphics_make_color(0x00, 0x00, 0x00, 0xFF); //bg
|
|
forecolor_menu = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //fg
|
|
|
|
graphics_set_color (list_font_color, backcolor);
|
|
|
|
u8 c_pos[MAX_LIST+1];
|
|
int c_pos_counter=0;
|
|
|
|
c_pos[c_pos_counter++]=0;
|
|
|
|
u8 c_dirname[64];
|
|
|
|
if(page_display){
|
|
|
|
u8 pi = page/20;
|
|
u8 ci=0;
|
|
|
|
if(count%20==0)
|
|
ci = (count-1)/20;
|
|
else
|
|
ci = count/20;
|
|
sprintf(c_dirname, "%i/%i SD:/%s", pi+1, ci+1, pwd);
|
|
}
|
|
else{
|
|
sprintf(c_dirname, "SD:/%s", pwd);
|
|
}
|
|
char sel_str[128];
|
|
|
|
printText(c_dirname, 3, 4, disp);
|
|
|
|
int firstrun=1;
|
|
/* Page bounds checking */
|
|
if(max > count) { //count = directories starting at 1
|
|
max = count;
|
|
}
|
|
|
|
/* Cursor bounds checking */
|
|
if(cursor >= (page + max)) {
|
|
cursor = (page + max) - 1;
|
|
}
|
|
|
|
if(cursor < page) {
|
|
cursor = page;
|
|
}
|
|
|
|
if( max == 0 ) {
|
|
printText("dir empty...", 3, 6, disp);
|
|
sprintf(sel_str, "dir empty...");
|
|
empty=1;
|
|
}
|
|
else {
|
|
empty=0;
|
|
}
|
|
|
|
//last page anti ghosting entries
|
|
if(page == (count/20)*20)
|
|
max=count%20;
|
|
|
|
for(int i = page; i < (page + max); i++) {//from page to page + max
|
|
if(list[i].type == DT_DIR) {
|
|
char tmpdir[(CONSOLE_WIDTH-5)+1];
|
|
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-5);
|
|
|
|
tmpdir[CONSOLE_WIDTH-5] = 0;
|
|
|
|
char *dir_str;
|
|
dir_str = malloc(slen(tmpdir)+3);
|
|
|
|
if(i == cursor){
|
|
sprintf(dir_str, " [%s]", tmpdir);
|
|
sprintf(sel_str, " [%s]", tmpdir);
|
|
|
|
if(scroll_behaviour)
|
|
drawSelection(disp,i);
|
|
|
|
c_pos[c_pos_counter++]=1;
|
|
}
|
|
else{
|
|
sprintf(dir_str, "[%s]", tmpdir);
|
|
c_pos[c_pos_counter++]=0;
|
|
}
|
|
graphics_set_color (list_dir_font_color, backcolor);
|
|
if(firstrun){
|
|
printText(dir_str, 3, 6, disp);
|
|
firstrun=0;
|
|
}
|
|
else{
|
|
printText(dir_str, 3, -1, disp);
|
|
}
|
|
free(dir_str);
|
|
}
|
|
else { //if(list[i].type == DT_REG)
|
|
int fcolor=list[i].color;
|
|
|
|
if(fcolor!=0){
|
|
switch(fcolor){
|
|
case 1: forecolor = graphics_make_color(0xFF, 0xFF, 0xFF, 0xFF); //common (white)
|
|
break;
|
|
case 2: forecolor = graphics_make_color(0x00, 0xFF, 0x00, 0xCF); //uncommon (green)
|
|
break;
|
|
case 3: forecolor = graphics_make_color(0x1E, 0x90, 0xFF, 0xFF); //rare (blue)
|
|
break;
|
|
case 4: forecolor = graphics_make_color(0x9B, 0x30, 0xFF, 0xFF); //epic (purple)
|
|
break;
|
|
case 5: forecolor = graphics_make_color(0xFF, 0xA5, 0x00, 0xFF); //legendary (orange)
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
forecolor = list_font_color;
|
|
|
|
char tmpdir[(CONSOLE_WIDTH-3)+1];
|
|
strncpy(tmpdir, list[i].filename, CONSOLE_WIDTH-3);
|
|
tmpdir[CONSOLE_WIDTH-3] = 0;
|
|
|
|
char *dir_str;
|
|
dir_str = malloc(slen(tmpdir)+1);
|
|
|
|
if(i == cursor){
|
|
sprintf(dir_str, " %s", tmpdir);
|
|
sprintf(sel_str, " %s", tmpdir);
|
|
|
|
if(scroll_behaviour)
|
|
drawSelection(disp,i);
|
|
|
|
c_pos[c_pos_counter++]=1;
|
|
}
|
|
else{
|
|
sprintf(dir_str, "%s", tmpdir);
|
|
c_pos[c_pos_counter++]=0;
|
|
}
|
|
|
|
graphics_set_color(list_font_color, backcolor);
|
|
|
|
if(firstrun){
|
|
if(enable_colored_list)
|
|
graphics_set_color(forecolor, backcolor);
|
|
|
|
printText(dir_str, 3, 6, disp); //3,6
|
|
firstrun=0;
|
|
}
|
|
else{
|
|
if(enable_colored_list)
|
|
graphics_set_color(forecolor, backcolor);
|
|
|
|
printText(dir_str, 3, -1, disp); //3,1
|
|
}
|
|
free(dir_str);
|
|
}
|
|
}
|
|
|
|
//for page-wise scrolling
|
|
if(scroll_behaviour==0){
|
|
int c=0;
|
|
for(c=0;c<max+1;c++){
|
|
if(c_pos[c]==1){
|
|
drawSelection(disp,c-1);
|
|
//todo: set selection color
|
|
graphics_set_color(selection_font_color, backcolor);
|
|
printText(sel_str, 3, 6+c-1, disp);
|
|
graphics_set_color(forecolor, backcolor);
|
|
}
|
|
}
|
|
}
|
|
graphics_set_color(forecolor_menu, backcolor);
|
|
}
|
|
|
|
|
|
void printText(char *msg, int x, int y, display_context_t dcon) {
|
|
x=x+text_offset;
|
|
|
|
if (x != -1)
|
|
gCursorX = x;
|
|
if (y != -1)
|
|
gCursorY = y;
|
|
|
|
if (dcon)
|
|
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg);
|
|
|
|
gCursorY++;
|
|
if (gCursorY > 29) {
|
|
gCursorY = 0;
|
|
gCursorX ++;
|
|
}
|
|
}
|
|
|
|
void lprintText(char *msg, int x, int y, display_context_t dcon) {
|
|
x=x+text_offset;
|
|
|
|
if (x != -1)
|
|
gCursorX = x;
|
|
if (y != -1)
|
|
gCursorY = y;
|
|
|
|
if (dcon)
|
|
graphics_draw_text(dcon, gCursorX*8, gCursorY*8, msg);
|
|
|
|
if (gCursorY > 29) {
|
|
gCursorY = 0;
|
|
gCursorX ++;
|
|
}
|
|
}
|
|
|
|
//background sprite
|
|
void drawBg(display_context_t disp){
|
|
graphics_draw_sprite( disp, 0, 0, background );
|
|
}
|
|
|
|
void drawBox(short x, short y, short width, short height, display_context_t disp){
|
|
x=x+(text_offset*8);
|
|
|
|
/*
|
|
* |Y
|
|
* | x0/y0
|
|
* |
|
|
* |
|
|
* | x1/y1
|
|
* |_______________X
|
|
*
|
|
*/
|
|
|
|
// X0 Y0 X1 Y1
|
|
graphics_draw_line(disp, x, y, width+x, y, border_color_1); //A top left tp bottom right ok
|
|
graphics_draw_line(disp, width+x, y, width+x, height+y, border_color_1); //B top right to bottom right
|
|
graphics_draw_line(disp, x, y, x, height+y, border_color_2); //C //152-20
|
|
graphics_draw_line(disp, x, height+y, width+x, height+y, border_color_2); //D
|
|
graphics_draw_box_trans(disp, x+1, y+1, width-1, height-1, box_color); //red light transparent
|
|
}
|
|
|
|
void drawBoxNumber(display_context_t disp, int box){
|
|
int old_color = box_color;
|
|
//backup color
|
|
|
|
switch(box){
|
|
case 1: drawBox(20, 24, 277, 193, disp); break; //filebrowser
|
|
case 2: drawBox(60, 64, 197, 114, disp); break; //info screen
|
|
case 3:
|
|
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC9);
|
|
drawBox(79, 29, 161, 180, disp);
|
|
break; //cover
|
|
case 4:
|
|
box_color= graphics_make_color(0x30, 0x00, 0x00, 0xA3);
|
|
drawBox(79, 29, 161, 180, disp);
|
|
break; //mempak content
|
|
case 5:
|
|
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3);
|
|
drawBox(60, 64, 197, 114, disp); //red confirm screen
|
|
break; //mempak content
|
|
case 6:
|
|
box_color= graphics_make_color(0x60, 0x60, 0x00, 0xC3);
|
|
drawBox(60, 64, 197, 125, disp); //yellow screen
|
|
break; //rom config box
|
|
case 7:
|
|
box_color= graphics_make_color(0x00, 0x00, 0x60, 0xC3);
|
|
drawBox(60, 105, 197, 20, disp); //blue info screen
|
|
break; //info screen
|
|
case 8:
|
|
box_color= graphics_make_color(0x60, 0x00, 0x00, 0xD3);
|
|
drawBox(60, 105, 197, 20, disp); //red error screen
|
|
break; //info screen
|
|
case 9:
|
|
box_color= graphics_make_color(0x00, 0x00, 0x00, 0xB6);
|
|
drawBox(28, 49, 260, 150, disp);
|
|
break; //yellow toplist
|
|
case 10:
|
|
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3);
|
|
drawBox(60, 105, 197, 20, disp); //green info screen
|
|
break; //info screen
|
|
case 11:
|
|
box_color= graphics_make_color(0x00, 0x60, 0x00, 0xC3);
|
|
drawBox(28, 105, 260, 30, disp);
|
|
break; //green full filename
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
//restore color
|
|
box_color=old_color;
|
|
}
|
|
|
|
//is setting the config file vars into the pconfig-structure
|
|
static int configHandler(void* user, const char* section, const char* name, const char* value) {
|
|
configuration* pconfig = (configuration*)user;
|
|
|
|
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
|
|
|
|
if (MATCH("ed64", "border_color_1")) {
|
|
pconfig->border_color_1 = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "border_color_2")) {
|
|
pconfig->border_color_2 = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "box_color")) {
|
|
pconfig->box_color = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "selection_color")) {
|
|
pconfig->selection_color = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "list_font_color")) {
|
|
pconfig->list_font_color = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "list_dir_font_color")) {
|
|
pconfig->list_dir_font_color = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "selection_font_color")) {
|
|
pconfig->selection_font_color = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "mempak_path")) {
|
|
pconfig->mempak_path = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "save_path")) {
|
|
pconfig->save_path = strdup(value);
|
|
}
|
|
else if (MATCH("ed64", "sound_on")) {
|
|
pconfig->sound_on = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "page_display")) {
|
|
pconfig->page_display = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "tv_mode")) {
|
|
pconfig->tv_mode = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "quick_boot")) {
|
|
pconfig->quick_boot = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "enable_colored_list")) {
|
|
pconfig->enable_colored_list = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "ext_type")) {
|
|
pconfig->ext_type = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "cd_behaviour")) {
|
|
pconfig->cd_behaviour = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "scroll_behaviour")) {
|
|
pconfig->scroll_behaviour = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "text_offset")) {
|
|
pconfig->text_offset = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "sd_speed")) {
|
|
pconfig->sd_speed = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "hide_sysfolder")) {
|
|
pconfig->hide_sysfolder = atoi(value);
|
|
}
|
|
else if (MATCH("ed64", "background_image")) {
|
|
pconfig->background_image = strdup(value);
|
|
}
|
|
else if (MATCH("user", "name")) {
|
|
pconfig->name = strdup(value);
|
|
}
|
|
|
|
else {
|
|
return 0; /* unknown section/name, error */
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
//everdrive init functions
|
|
void configure() {
|
|
u16 tv;
|
|
u16 msg = 0;
|
|
u16 sd_mode = 0;
|
|
u8 buff[16];
|
|
u16 firm;
|
|
|
|
evd_init();
|
|
//REG_MAX_MSG
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 0);
|
|
dma_read_s(buff, ROM_ADDR + 0x20, 16);
|
|
asm_date = memRomRead32(0x38);
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
|
|
|
|
firm = evd_readReg(REG_VER);
|
|
|
|
if (streql("ED64 SD boot", buff, 12) && firm >= 0x0116) {
|
|
sd_mode = 1;
|
|
}
|
|
|
|
if (firm >= 0x0200) {
|
|
sleep(1);
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 0);
|
|
sleep(1);
|
|
|
|
msg = evd_readReg(REG_MAX_MSG);
|
|
|
|
if (!(msg & (1 << 14))) {
|
|
msg |= 1 << 14;
|
|
evd_writeReg(REG_MAX_MSG, msg);
|
|
|
|
bi_load_firmware(firmware);
|
|
|
|
sleep(1);
|
|
evd_init();
|
|
}
|
|
sleep(1);
|
|
|
|
evd_setCfgBit(ED_CFG_SDRAM_ON, 1);
|
|
}
|
|
|
|
if (sd_mode) {
|
|
diskSetInterface(DISK_IFACE_SD);
|
|
} else {
|
|
diskSetInterface(DISK_IFACE_SPI);
|
|
}
|
|
memSpiSetDma(0);
|
|
}
|
|
|
|
//rewrites the background and the box to clear the screen
|
|
void clearScreen(display_context_t disp){
|
|
drawBg(disp); //background
|
|
drawBoxNumber(disp,1); //filebrowser box
|
|
}
|
|
|
|
void romInfoScreen(display_context_t disp, u8 *buff, int silent){
|
|
if(silent!=1)
|
|
sleep(10);
|
|
|
|
u8 tmp[32];
|
|
u8 filename[64];
|
|
u8 ok=0;
|
|
|
|
sprintf(filename, "%s",buff);
|
|
int swapped=0;
|
|
|
|
FatRecord rec_tmpf;
|
|
//not needed any longer :>
|
|
//file IS there, it's selected at this point
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
|
|
u8 resp = 0;
|
|
|
|
resp = fatOpenFileByeName(filename, 0); //err if not found ^^
|
|
|
|
int mb = file.sec_available/2048;
|
|
int block_offset = 0;
|
|
u32 cart_buff_offset = 0;
|
|
u32 begin_sector = file.sector;
|
|
|
|
//filesize -> readfile / 512
|
|
int fsize=512; //rom-headersize 4096 but the bootcode is not needed
|
|
unsigned char headerdata[fsize]; //1*512
|
|
|
|
resp = fatReadFile(&headerdata, fsize / 512); //1 cluster
|
|
|
|
int sw_type=is_valid_rom(headerdata);
|
|
|
|
if(sw_type!=0){
|
|
swapped=1;
|
|
swap_header(headerdata, 512);
|
|
}
|
|
|
|
//char 32-51 name
|
|
unsigned char rom_name[32];
|
|
|
|
for(int u=0; u<19;u++){
|
|
if(u!=0)
|
|
sprintf(rom_name, "%s%c", rom_name, headerdata[32+u]);
|
|
else
|
|
sprintf(rom_name, "%c", headerdata[32+u]);
|
|
}
|
|
//trim right spaces
|
|
//romname=trimmed rom name for filename
|
|
sprintf(rom_name, "%s", trim(rom_name));
|
|
|
|
if(silent!=1)
|
|
printText(rom_name, 11, 19, disp);
|
|
|
|
sprintf(rom_name, "Size: %iMb", mb);
|
|
|
|
if(silent!=1)
|
|
printText(rom_name, 11, -1, disp);
|
|
|
|
//unique cart id for gametype
|
|
unsigned char cartID_str[12];
|
|
sprintf(cartID_str, "ID: %c%c%c%c", headerdata[0x3B], headerdata[0x3C], headerdata[0x3D], headerdata[0x3E]);
|
|
|
|
if(silent!=1)
|
|
printText(cartID_str, 11, -1, disp);
|
|
|
|
int cic, save;
|
|
|
|
cic = get_cic(&headerdata[0x40]);
|
|
|
|
unsigned char cartID_short[4];
|
|
sprintf(cartID_short, "%c%c\0", headerdata[0x3C], headerdata[0x3D]);
|
|
|
|
if (get_cic_save(cartID_short, &cic, &save)) {
|
|
if(silent!=1)
|
|
printText("found in db", 11, -1, disp);
|
|
unsigned char save_type_str[12];
|
|
sprintf(save_type_str, "Save: %s", saveTypeToExtension(save,ext_type));
|
|
if(silent!=1)
|
|
printText(save_type_str, 11, -1, disp);
|
|
|
|
unsigned char cic_type_str[12];
|
|
sprintf(cic_type_str, "CIC: CIC-610%i", cic);
|
|
if(silent!=1)
|
|
printText(cic_type_str, 11, -1, disp);
|
|
|
|
//thanks for the db :>
|
|
//cart was found, use CIC and SaveRAM type
|
|
}
|
|
|
|
if(silent!=1){
|
|
char box_path[32];
|
|
|
|
sprite_t *n64cover;
|
|
|
|
sprintf(box_path, "/ED64/boxart/lowres/%c%c.png", headerdata[0x3C], headerdata[0x3D]);
|
|
|
|
int found;
|
|
|
|
found = fatFindRecord(box_path, &rec_tmpf, 0);
|
|
|
|
if(found!=0){
|
|
//not found
|
|
sprintf(box_path, "/ED64/boxart/lowres/00.png");
|
|
}
|
|
|
|
n64cover = loadPng(box_path);
|
|
graphics_draw_sprite( disp, 81, 32, n64cover );
|
|
display_show(disp);
|
|
}
|
|
else {
|
|
rom_config[1]=cic-1;
|
|
rom_config[2]=save;
|
|
rom_config[3]=0; //tv force off
|
|
rom_config[4]=0; //cheat off
|
|
rom_config[5]=0; //chk_sum off
|
|
rom_config[6]=0; //rating
|
|
rom_config[7]=0; //country
|
|
rom_config[8]=0; //reserved
|
|
rom_config[9]=0; //reserved
|
|
}
|
|
}
|
|
|
|
|
|
sprite_t *loadPng(u8 *png_filename){
|
|
u8 *filename;
|
|
u8 ok=0;
|
|
|
|
filename = (u8 *) malloc(slen(png_filename));
|
|
//config filename
|
|
|
|
sprintf(filename, "%s",png_filename);
|
|
FatRecord rec_tmpf;
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(filename, 0);
|
|
|
|
//filesize of the opend file -> is the readfile / 512
|
|
int fsize= file.sec_available*512;
|
|
|
|
u8 png_rawdata[fsize];
|
|
|
|
resp = fatReadFile(&png_rawdata, fsize / 512); //1 cluster
|
|
|
|
return loadImage32(png_rawdata, fsize);
|
|
|
|
free(filename);
|
|
}
|
|
|
|
void loadgbrom(display_context_t disp, u8 *buff){
|
|
FatRecord rec_tmpf;
|
|
|
|
u8 exist=0;
|
|
exist = fatFindRecord("/ED64/gblite.z64", &rec_tmpf, 0); //filename already exists
|
|
|
|
if (exist == 0) {
|
|
u8 gb_sram_file[64];
|
|
|
|
u8 resp=0;
|
|
|
|
sprintf(gb_sram_file, "/ED64/%s/gblite.SRM",save_path);
|
|
|
|
resp = fatFindRecord(gb_sram_file, &rec_tmpf, 0); //filename already exists
|
|
resp = fatCreateRecIfNotExist(gb_sram_file, 0);
|
|
resp = fatOpenFileByeName(gb_sram_file, 32768 / 512);
|
|
|
|
static uint8_t sram_buffer[36928];
|
|
|
|
for(int i=0;i<36928;i++)
|
|
sram_buffer[i]=0;
|
|
|
|
sprintf(sram_buffer, buff);
|
|
|
|
resp = fatWriteFile(&sram_buffer, 32768 / 512);
|
|
|
|
while( !(disp = display_lock()) );
|
|
|
|
sprintf(rom_filename, "gblite");
|
|
gbload=1;
|
|
|
|
loadrom(disp, "/ED64/gblite.z64", 1);
|
|
}
|
|
}
|
|
|
|
void loadmsx2rom(display_context_t disp, u8 *rom_path){
|
|
//max 128kb rom
|
|
int max_ok = fatOpenFileByeName(rom_path, 0);
|
|
int fsize = file.sec_available*512; //fsize in bytes
|
|
|
|
if(fsize>128*1024){
|
|
//error
|
|
|
|
drawShortInfoBox(disp, " error: rom > 128kB",1);
|
|
input_mapping=98;
|
|
|
|
return;
|
|
}
|
|
else{
|
|
drawShortInfoBox(disp, " loading please wait",0);
|
|
input_mapping=100;//disable all
|
|
}
|
|
|
|
FatRecord rec_tmpf;
|
|
|
|
u8 exist=0;
|
|
exist = fatFindRecord("/ED64/ultraMSX2.z64", &rec_tmpf, 0); //filename already exists
|
|
|
|
if (exist == 0) {
|
|
u8 resp=0;
|
|
//load nes emulator
|
|
resp = fatOpenFileByeName("/ED64/ultraMSX2.z64", 0); //err if not found ^^
|
|
|
|
int fsize=1024*1024;
|
|
u8 buffer[fsize];
|
|
|
|
//injecting in buffer... slow but working :/
|
|
resp = fatReadFile(buffer, file.sec_available);
|
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^
|
|
resp = fatReadFile(buffer+0x2df48, file.sec_available);
|
|
dma_write_s(buffer, 0xb0000000, fsize);
|
|
|
|
boot_cic=2; //cic 6102
|
|
boot_save=0; //save off/cpak
|
|
force_tv=0; //no force
|
|
cheats_on=0; //cheats off
|
|
checksum_fix_on=0;
|
|
|
|
checksum_sdram();
|
|
|
|
bootRom(disp, 1);
|
|
}
|
|
}
|
|
|
|
|
|
void loadggrom(display_context_t disp, u8 *rom_path){
|
|
//max 512kb rom
|
|
int max_ok = fatOpenFileByeName(rom_path, 0);
|
|
int fsize = file.sec_available*512; //fsize in bytes
|
|
|
|
if(fsize>512*1024){
|
|
//error
|
|
drawShortInfoBox(disp, " error: rom > 512kB",1);
|
|
input_mapping=98;
|
|
|
|
return;
|
|
}
|
|
else{
|
|
drawShortInfoBox(disp, " loading please wait",0);
|
|
input_mapping=100;//disable all
|
|
}
|
|
|
|
FatRecord rec_tmpf;
|
|
|
|
u8 exist=0;
|
|
exist = fatFindRecord("/ED64/UltraSMS.z64", &rec_tmpf, 0); //filename already exists
|
|
|
|
if (exist == 0) {
|
|
u8 resp=0;
|
|
//load nes emulator
|
|
resp = fatOpenFileByeName("/ED64/UltraSMS.z64", 0); //err if not found ^^
|
|
|
|
int fsize=1024*1024;
|
|
u8 buffer[fsize];
|
|
|
|
//injecting in buffer... slow but working :/
|
|
resp = fatReadFile(buffer, file.sec_available);
|
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^
|
|
resp = fatReadFile(buffer+0x1b410, file.sec_available);
|
|
dma_write_s(buffer, 0xb0000000, fsize);
|
|
|
|
boot_cic=2; //cic 6102
|
|
boot_save=0; //save off/cpak
|
|
force_tv=0; //no force
|
|
cheats_on=0; //cheats off
|
|
checksum_fix_on=0;
|
|
|
|
checksum_sdram();
|
|
|
|
bootRom(disp, 1);
|
|
}
|
|
}
|
|
|
|
void rom_load_y(void){
|
|
FatRecord rec_tmpf;
|
|
|
|
u8 gb_sram_file[64];
|
|
u8 gb_sram_file2[64];
|
|
sprintf(gb_sram_file, "%c%c%c%c%c%c%c",'O', 'S', '6', '4', 'P', '/', 'O');
|
|
sprintf(gb_sram_file2, "%s%c%c%c%c%c%c%c%c", gb_sram_file, 'S', '6', '4', 'P', '.', 'v', '6', '4');
|
|
|
|
u8 exist=0;
|
|
exist = fatFindRecord(gb_sram_file2, &rec_tmpf, 0); //filename already exists
|
|
if (exist == 0) {
|
|
gb_load_y=1;
|
|
}
|
|
}
|
|
|
|
void loadnesrom(display_context_t disp, u8 *rom_path){
|
|
FatRecord rec_tmpf;
|
|
|
|
u8 exist=0;
|
|
exist = fatFindRecord("/ED64/neon64bu.rom", &rec_tmpf, 0); //filename already exists
|
|
|
|
if (exist == 0) {
|
|
u8 resp=0;
|
|
//load nes emulator
|
|
resp = fatOpenFileByeName("/ED64/neon64bu.rom", 0); //err if not found ^^
|
|
resp = diskRead(file.sector, (void *)0xb0000000, file.sec_available);
|
|
|
|
//load nes rom
|
|
resp = fatOpenFileByeName(rom_path, 0); //err if not found ^^
|
|
resp = diskRead(file.sector, (void *)0xb0200000, file.sec_available);
|
|
|
|
boot_cic=2; //cic 6102
|
|
boot_save=0; //save off/cpak
|
|
force_tv=0; //no force
|
|
cheats_on=0; //cheats off
|
|
checksum_fix_on=0;
|
|
|
|
bootRom(disp, 1);
|
|
}
|
|
}
|
|
|
|
//load a z64/v64/n64 rom to the sdram
|
|
void loadrom(display_context_t disp, u8 *buff, int fast){
|
|
clearScreen(disp);
|
|
|
|
display_show(disp);
|
|
|
|
if(!fast)
|
|
printText("Restoring:", 3, 4, disp);
|
|
|
|
sleep(10);
|
|
sleep(1000); //needless waiting :>
|
|
|
|
if (debug)
|
|
printText("timing done", 3, -1, disp);
|
|
|
|
u8 tmp[32];
|
|
u8 filename[64];
|
|
u8 ok=0;
|
|
|
|
sprintf(filename, "%s",buff);
|
|
int swapped=0;
|
|
|
|
if (debug)
|
|
printText(buff, 3, -1, disp);
|
|
|
|
FatRecord rec_tmpf;
|
|
//not needed any longer :>
|
|
//file IS there, it's selected at this point
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
if (debug)
|
|
printText("found", 3, -1, disp);
|
|
|
|
u8 resp = 0;
|
|
|
|
resp = fatOpenFileByeName(filename, 0); //err if not found ^^
|
|
|
|
if (debug)
|
|
printText("opened", 3, -1, disp);
|
|
|
|
int mb = file.sec_available/2048;
|
|
int file_sectors = file.sec_available;
|
|
int block_offset = 0;
|
|
u32 cart_buff_offset = 0;
|
|
u32 begin_sector = file.sector;
|
|
|
|
//filesize -> readfile / 512
|
|
int fsize=512; //rom-headersize 4096 but the bootcode is not needed
|
|
unsigned char headerdata[fsize]; //1*512
|
|
|
|
resp = fatReadFile(&headerdata, fsize / 512); //1 cluster
|
|
|
|
int sw_type=is_valid_rom(headerdata);
|
|
|
|
if(sw_type!=0){
|
|
if(!fast)
|
|
printText("byteswapped file", 3, -1, disp);
|
|
|
|
swapped=1;
|
|
swap_header(headerdata, 512);
|
|
}
|
|
|
|
//char 32-51 name
|
|
unsigned char rom_name[32];
|
|
|
|
for(int u=0; u<19;u++){
|
|
if(u!=0)
|
|
sprintf(rom_name, "%s%c", rom_name, headerdata[32+u]);
|
|
else
|
|
sprintf(rom_name, "%c", headerdata[32+u]);
|
|
}
|
|
//trim right spaces
|
|
//romname=trimmed rom name for filename
|
|
sprintf(rom_name, "%s", trim(rom_name));
|
|
|
|
if(!fast)
|
|
printText(rom_name, 3, -1, disp);
|
|
|
|
//unique cart id for gametype
|
|
|
|
sprintf(cartID, "%c%c%c%c", headerdata[0x3B], headerdata[0x3C], headerdata[0x3D], headerdata[0x3E]);
|
|
|
|
int cic, save;
|
|
|
|
cic = get_cic(&headerdata[0x40]);
|
|
|
|
unsigned char cartID_short[4];
|
|
sprintf(cartID_short, "%c%c\0", headerdata[0x3C], headerdata[0x3D]);
|
|
|
|
if (get_cic_save(cartID_short, &cic, &save)) {
|
|
if(!fast)
|
|
printText("found in db", 3, -1, disp);
|
|
//thanks for the db :>
|
|
// cart was found, use CIC and SaveRAM type
|
|
}
|
|
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "Info: cic=%i save=%i",cic,save);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
}
|
|
|
|
//new rom_config
|
|
boot_cic=rom_config[1]+1;
|
|
boot_save=rom_config[2];
|
|
force_tv=rom_config[3];
|
|
cheats_on=rom_config[4];
|
|
checksum_fix_on=rom_config[5];
|
|
boot_country=rom_config[7]; //boot_block
|
|
|
|
if (gbload==1)
|
|
boot_save=1;
|
|
|
|
else if (resp) {
|
|
sprintf(tmp, "resp: %i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
if (debug)
|
|
printText("enalbe sd_mode", 3, -1, disp);
|
|
|
|
resp = evd_isSDMode();
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "sdmode: %i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
sprintf(tmp, "Size: %i", file.sec_available);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
sprintf(tmp, "f_sector: %i", file.sector);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
printText("loading:", 3, -1, disp);
|
|
}
|
|
sleep(10);
|
|
|
|
if(swapped==1){
|
|
while (evd_isDmaBusy());
|
|
sleep(400);
|
|
evd_mmcSetDmaSwap(1);
|
|
|
|
if (debug)
|
|
printText("swapping on", 3, -1, disp);
|
|
|
|
sleep(10);
|
|
}
|
|
|
|
if(!fast)
|
|
printText("loading please wait...", 3, -1, disp);
|
|
else
|
|
printText("loading please wait...", 3, 4, disp);
|
|
|
|
sleep(10);
|
|
|
|
int lower_half=2048*32;
|
|
|
|
if(mb<=32){
|
|
resp = diskRead(begin_sector, (void *)0xb0000000, file_sectors); //2048 cluster 1Mb
|
|
}
|
|
else{
|
|
resp = diskRead(begin_sector, (void *)0xb0000000, lower_half);
|
|
sleep(10);
|
|
resp = diskRead(begin_sector+lower_half, (void *)0xb2000000, file_sectors-lower_half);
|
|
}
|
|
|
|
if(resp){
|
|
if (debug) {
|
|
sprintf(tmp, "mmcToCart: %i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
}
|
|
|
|
if (debug)
|
|
for (int i = 0; i < 4; i++) {
|
|
u8 buff[16];
|
|
dma_read_s(buff, 0xb0000000 + 0x00100000*i, 1);
|
|
sprintf(tmp, "probe: %hhx",buff[0]);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
}
|
|
|
|
if(!fast){
|
|
sleep(200);
|
|
|
|
printText(" ", 3, -1, disp);
|
|
printText("(C-UP to activate cheats)", 3, -1, disp);
|
|
printText("(C-RIGHT to force menu tv mode)", 3, -1, disp);
|
|
printText("done: PRESS START", 3, -1, disp);
|
|
}
|
|
else{
|
|
bootRom(disp, 1);
|
|
}
|
|
}
|
|
|
|
|
|
int backupSaveData(display_context_t disp){
|
|
//backup cart-save on sd after reboot
|
|
u8 fname[32];
|
|
u8 found=0;
|
|
int save_t;
|
|
|
|
sprintf(fname, "/ED64/%s/LAST.CRT",save_path);
|
|
uint8_t cfg_data[512];
|
|
|
|
FatRecord rec_tmpf;
|
|
found = fatFindRecord(fname, &rec_tmpf, 0);
|
|
|
|
printText("Save System - please stand by", 3, 4, disp);
|
|
|
|
if(found==0){
|
|
//found
|
|
|
|
//file to cfg_data buffer
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(fname, 0);
|
|
resp = fatReadFile(&cfg_data, 1);
|
|
|
|
//split in save type and cart-id
|
|
save_t=cfg_data[0];
|
|
int last_cic=cfg_data[1];
|
|
scopy(cfg_data+2, rom_filename);
|
|
|
|
//set savetype to 0 disable for next boot
|
|
if(save_t!=0){
|
|
//set savetype to off
|
|
cfg_data[0]=0;
|
|
|
|
u8 tmp[32];
|
|
|
|
resp = fatOpenFileByeName(fname, 1); //if sector is set filemode=WR writeable
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
resp = fatWriteFile(&cfg_data, 1); //filemode must be wr
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatWriteFile ret=%i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
|
|
printText("SaveType-tag has been disabled for next boot", 3, -1, disp);
|
|
}
|
|
|
|
volatile u8 save_cfg_stat=0;
|
|
volatile u8 val=0;
|
|
val = evd_readReg(0);
|
|
save_cfg_stat = evd_readReg(REG_SAV_CFG);
|
|
|
|
if(save_cfg_stat!=0)
|
|
save_reboot=1;
|
|
}
|
|
else {
|
|
if (debug)
|
|
printText("no need to save to sd", 3, -1, disp);
|
|
else
|
|
printText("...ready", 3, -1, disp);
|
|
|
|
sleep(200);
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
else{
|
|
if (debug)
|
|
printText("last.crt not found", 3, -1, disp);
|
|
else
|
|
printText("...ready", 3, -1, disp);
|
|
|
|
return 0;
|
|
}
|
|
|
|
if (debug) {
|
|
sleep(5000);
|
|
}
|
|
|
|
//reset with save request
|
|
if(save_reboot){
|
|
printText("saving...", 3, -1, disp);
|
|
if( saveTypeToSd(disp, rom_filename, save_t) ){
|
|
if (debug)
|
|
printText("save upload done...", 3, -1, disp);
|
|
else
|
|
printText("...ready", 3, -1, disp);
|
|
}
|
|
else if (debug)
|
|
printText("not saved...", 3, -1, disp);
|
|
}
|
|
else {
|
|
if (debug)
|
|
printText("no reset - save request", 3, -1, disp);
|
|
else
|
|
printText("...ready", 3, -1, disp);
|
|
|
|
sleep(300);
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
//old method to write a file to the mempak at controller 1
|
|
void file_to_mpk(display_context_t disp, u8 *filename){
|
|
u8 tmp[32];
|
|
u8 buff[64];
|
|
u8 ok=0;
|
|
|
|
printText(filename, 9, -1, disp);
|
|
FatRecord rec_tmpf;
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(filename, 0);
|
|
|
|
u8 *pch;
|
|
pch=strrchr(filename,'.');
|
|
sprintf(buff, "%s",(pch+2));
|
|
|
|
if(strcmp(buff,"64")==0){
|
|
printText("Dexdrive format", 9, -1, disp);
|
|
printText("skip header", 9, -1, disp);
|
|
|
|
static uint8_t mempak_data_buff[36928];
|
|
resp = fatReadFile(&mempak_data_buff, 36928 / 512);
|
|
|
|
memcpy( &mempak_data, mempak_data_buff+4160, 32768);
|
|
}
|
|
else {
|
|
printText("Z64 format", 9, -1, disp);
|
|
resp = fatReadFile(&mempak_data, 32768 / 512);
|
|
}
|
|
|
|
int err = 0;
|
|
for( int j = 0; j < 128; j++ ) {
|
|
err |= write_mempak_sector( 0, j, &mempak_data[j * MEMPAK_BLOCK_SIZE] );
|
|
}
|
|
}
|
|
|
|
char TranslateNotes( char *bNote, char *Text ) {
|
|
#pragma warning( disable : 4305 4309 )
|
|
char cReturn = 0x00;
|
|
const char aSpecial[] = { 0x21, 0x22, 0x23, 0x60, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x3A, 0x3D, 0x3F, 0x40, 0x74, 0xA9, 0xAE };
|
|
// { '!' , '\"', '#' , '`' , '*' , '+' , ',' , '-' , '.' , '/' , ':' , '=' , '?' , '>' , 'tm', '(r)','(c)' };
|
|
#pragma warning( default : 4305 4309 )
|
|
int i = 16;
|
|
do {
|
|
char b = bNote[i];
|
|
if(( b > 0 ) && i < 32 ) {
|
|
if( b <= 0x0F ) // translate Icons as Spaces
|
|
*Text = 0x20;
|
|
else if( b <= 0x19 ) // Numbers
|
|
*Text = 0x20 + b;
|
|
else if( b <= 0x33 ) // Characters
|
|
*Text = 0x47 + b;
|
|
else if( b <= 0x44 ) // special Symbols
|
|
*Text = aSpecial[b - 0x34];
|
|
else if( b <= 0x94 ) // Japan
|
|
*Text = 0xC0 + ( b % 40 );
|
|
else // unknown
|
|
*Text = (char)0xA4;
|
|
|
|
++i;
|
|
++Text;
|
|
}
|
|
else {
|
|
*Text = '\0';
|
|
if( b ) {
|
|
i = 12;
|
|
Text = &cReturn;
|
|
}
|
|
else
|
|
i = 13;
|
|
}
|
|
} while( i != 13 );
|
|
|
|
return cReturn;
|
|
}
|
|
|
|
char CountBlocks( char *bMemPakBinary, char *aNoteSizes ) {
|
|
int wRemainingBlocks = 123;
|
|
char bNextIndex;
|
|
int i = 0;
|
|
while( i < 16 && wRemainingBlocks <= 123 ) {
|
|
aNoteSizes[i] = 0;
|
|
bNextIndex = bMemPakBinary[0x307 + (i*0x20)];
|
|
while(( bNextIndex >= 5 ) && ( aNoteSizes[i] < wRemainingBlocks)) {
|
|
aNoteSizes[i]++;
|
|
bNextIndex = bMemPakBinary[0x101 + (bNextIndex*2)];
|
|
}
|
|
|
|
if( aNoteSizes[i] > wRemainingBlocks )
|
|
wRemainingBlocks = 0xFF;
|
|
else
|
|
wRemainingBlocks -= aNoteSizes[i];
|
|
|
|
i++;
|
|
}
|
|
return wRemainingBlocks;
|
|
}
|
|
|
|
void view_mpk_file(display_context_t disp, char *mpk_filename){
|
|
u8 tmp[32];
|
|
u8 buff[64];
|
|
u8 ok=0;
|
|
|
|
FatRecord rec_tmpf;
|
|
ok = fatFindRecord(mpk_filename, &rec_tmpf, 0);
|
|
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(mpk_filename, 0);
|
|
|
|
u8 * pch;
|
|
pch=strrchr(mpk_filename,'.');
|
|
sprintf(buff, "%s",(pch+2));
|
|
|
|
if (strcmp(buff, "64") == 0) {
|
|
static uint8_t mempak_data_buff[36928];
|
|
resp = fatReadFile(&mempak_data_buff, 36928 / 512);
|
|
memcpy( &mempak_data, mempak_data_buff+4160, 32768);
|
|
}
|
|
else {
|
|
resp = fatReadFile(&mempak_data, 32768 / 512);
|
|
}
|
|
|
|
printText("File content:", 11, 5, disp);
|
|
printText(" ", 11, -1, disp);
|
|
|
|
int notes_c=0;
|
|
|
|
char szBuffer[40],
|
|
cAppendix;
|
|
int bFirstChar;
|
|
|
|
int i = 0,
|
|
nNotes = 0,
|
|
iSum = 0,
|
|
iRemainingBlocks;
|
|
|
|
char aNoteSizes[16];
|
|
|
|
for( i = 0x10A; i < 0x200; i++ )
|
|
iSum += mempak_data[i];
|
|
|
|
if((( iSum % 256 ) == mempak_data[0x101] )) {
|
|
iRemainingBlocks = CountBlocks( mempak_data, aNoteSizes );
|
|
|
|
if( iRemainingBlocks <= 123 ) {
|
|
for( notes_c = 0; notes_c < 16; notes_c++ ){
|
|
if( mempak_data[0x300 + (notes_c*32)] ||
|
|
mempak_data[0x301 + (notes_c*32)] ||
|
|
mempak_data[0x302 + (notes_c*32)] )
|
|
{
|
|
cAppendix = TranslateNotes( &mempak_data[0x300 + (notes_c*32)], szBuffer );
|
|
|
|
if( cAppendix != '\0' )
|
|
sprintf( szBuffer, "%s. %c", szBuffer, cAppendix );
|
|
|
|
bFirstChar = 1;
|
|
for( i = 0; i < (int)strlen(szBuffer); i++ ) {
|
|
if( szBuffer[i] == ' ' )
|
|
bFirstChar = 1;
|
|
else {
|
|
if( bFirstChar && ( szBuffer[i] >= 'a') && ( szBuffer[i] <= 'z')) {
|
|
bFirstChar = 0;
|
|
szBuffer[i] -= 0x20;
|
|
}
|
|
}
|
|
}
|
|
printText(szBuffer, 11, -1, disp);
|
|
|
|
switch( mempak_data[0x303 + (notes_c*32)] )
|
|
{
|
|
case 0x00:
|
|
sprintf( szBuffer, "None" );
|
|
break;
|
|
case 0x37:
|
|
sprintf( szBuffer, "Beta" );
|
|
break;
|
|
case 0x41:
|
|
sprintf( szBuffer, "NTSC" );
|
|
break;
|
|
case 0x44:
|
|
sprintf( szBuffer, "Germany" );
|
|
break;
|
|
case 0x45:
|
|
sprintf( szBuffer, "USA" );
|
|
break;
|
|
case 0x46:
|
|
sprintf( szBuffer, "France" );
|
|
break;
|
|
case 0x49:
|
|
sprintf( szBuffer, "Italy" );
|
|
break;
|
|
case 0x4A:
|
|
sprintf( szBuffer, "Japan" );
|
|
break;
|
|
case 0x50:
|
|
sprintf( szBuffer, "Europe" );
|
|
break;
|
|
case 0x53:
|
|
sprintf( szBuffer, "Spain" );
|
|
break;
|
|
case 0x55:
|
|
sprintf( szBuffer, "Australia" );
|
|
break;
|
|
case 0x58:
|
|
case 0x59:
|
|
sprintf( szBuffer, "PAL" );
|
|
break;
|
|
default:
|
|
sprintf( szBuffer, "Unknown(%02X)", mempak_data[0x303 + (notes_c*32)] );
|
|
}
|
|
|
|
sprintf( szBuffer, "%i", aNoteSizes[notes_c] );
|
|
nNotes++;
|
|
}
|
|
}
|
|
}
|
|
|
|
int free_c=0;
|
|
for(free_c=nNotes;free_c<16;free_c++)
|
|
printText("[free]", 11, -1, disp);
|
|
|
|
char buff[512];
|
|
printText(" ", 11, -1, disp);
|
|
printText("Free space:", 11, -1, disp);
|
|
sprintf(buff, "%i blocks", iRemainingBlocks );
|
|
printText(buff, 11, -1, disp);
|
|
}
|
|
else {
|
|
printText("empty", 11, -1, disp);
|
|
}
|
|
}
|
|
|
|
void view_mpk(display_context_t disp){
|
|
int err;
|
|
|
|
printText("Mempak content:", 11, 5, disp);
|
|
get_accessories_present();
|
|
|
|
/* Make sure they don't have a rumble pak inserted instead */
|
|
switch( identify_accessory( 0 ) )
|
|
{
|
|
case ACCESSORY_NONE:
|
|
|
|
printText(" ", 11, -1, disp);
|
|
printText("no Mempak", 11, -1, disp);
|
|
break;
|
|
|
|
case ACCESSORY_MEMPAK:
|
|
if( (err = validate_mempak( 0 )) ) {
|
|
if( err == -3 ) {
|
|
printText(" ", 11, -1, disp);
|
|
|
|
printText("not formatted", 11, -1, disp);
|
|
}
|
|
else {
|
|
printText(" ", 11, -1, disp);
|
|
printText("read error" , 11, -1, disp);
|
|
}
|
|
}
|
|
else {
|
|
printText(" ", 11, -1, disp);
|
|
for( int j = 0; j < 16; j++ ) {
|
|
entry_structure_t entry;
|
|
|
|
get_mempak_entry( 0, j, &entry );
|
|
|
|
if( entry.valid ) {
|
|
char tmp[512];
|
|
sprintf(tmp, "%s", entry.name );
|
|
printText(tmp, 11, -1, disp);
|
|
}
|
|
else {
|
|
printText("[free]", 11, -1, disp);
|
|
}
|
|
}
|
|
|
|
char buff[512];
|
|
printText(" ", 11, -1, disp);
|
|
printText("Free space:", 11, -1, disp);
|
|
sprintf(buff, "%d blocks", get_mempak_free_space( 0 ) );
|
|
printText(buff, 11, -1, disp);
|
|
}
|
|
break;
|
|
|
|
case ACCESSORY_RUMBLEPAK:
|
|
printText("rumblepak inserted", 11, -1, disp);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//old function to dump a mempak to a file
|
|
void mpk_to_file(display_context_t disp, char *mpk_filename, int quick) {
|
|
u8 buff[64];
|
|
u8 v=0;
|
|
u8 ok=0;
|
|
|
|
if(quick)
|
|
sprintf(buff, "%s%s",mempak_path, mpk_filename);
|
|
else
|
|
sprintf(buff, "%s%s.MPK",mempak_path,mpk_filename);
|
|
|
|
FatRecord rec_tmpf;
|
|
|
|
if(!fatFindRecord(buff, &rec_tmpf, 0)){ //filename already exists
|
|
printText("File exists", 9, -1, disp);
|
|
if(quick)
|
|
printText("override", 9, -1, disp);
|
|
else
|
|
while(ok==0){
|
|
sprintf(buff, "%s%s%i.MPK",mempak_path, mpk_filename,v);
|
|
|
|
ok = fatFindRecord(buff, &rec_tmpf, 0);
|
|
if (ok==0)
|
|
v++;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
|
u8 resp=0;
|
|
resp = fatCreateRecIfNotExist(buff, 0);
|
|
resp = fatOpenFileByeName(buff, 32768 / 512);
|
|
|
|
controller_init();
|
|
|
|
int err = 0;
|
|
for( int j = 0; j < 128; j++ ) {
|
|
err |= read_mempak_sector( 0, j, &mempak_data[j * 256] );
|
|
}
|
|
|
|
fatWriteFile(&mempak_data, 32768 / 512);
|
|
|
|
sleep(500);
|
|
|
|
sprintf(buff, "File: %s%i.MPK",mpk_filename,v);
|
|
|
|
printText(buff, 9, -1, disp);
|
|
printText("backup done...", 9, -1, disp);
|
|
}
|
|
|
|
//before boot_simulation
|
|
//writes a cart-save from a file to the fpga/cart
|
|
int saveTypeFromSd(display_context_t disp, char* rom_name, int stype) {
|
|
rom_load_y();
|
|
|
|
u8 tmp[32];
|
|
u8 fname[128];
|
|
u8 found=0;
|
|
|
|
int size;
|
|
size = saveTypeToSize(stype); // int byte
|
|
|
|
sprintf(fname, "/ED64/%s/%s.%s",save_path,rom_name, saveTypeToExtension(stype,ext_type));
|
|
|
|
uint8_t cartsave_data[size];
|
|
|
|
if (debug) {
|
|
printText(fname, 3, -1, disp);
|
|
sleep(2000);
|
|
}
|
|
|
|
FatRecord rec_tmpf;
|
|
found = fatFindRecord(fname, &rec_tmpf, 0);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatFindRecord ret=%i",found);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
if(found==0){
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(fname, 0);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
resp = fatReadFile(cartsave_data, size / 512);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatReadFile ret=%i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
}
|
|
else{
|
|
printText("no savegame found", 3, -1, disp);
|
|
//todo clear memory arena
|
|
|
|
return 0;
|
|
}
|
|
|
|
if(gb_load_y!=1) {
|
|
if( pushSaveToCart(stype, cartsave_data) ){
|
|
|
|
printText("save upload done...", 3, -1, disp);
|
|
}
|
|
else{
|
|
|
|
printText("pushSaveToCart error", 3, -1, disp);
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int saveTypeToSd(display_context_t disp, char* rom_name ,int stype) {
|
|
rom_load_y();
|
|
|
|
//after reset create new savefile
|
|
u8 tmp[32];
|
|
u8 fname[128]; //filename buffer to small :D
|
|
u8 found=0;
|
|
|
|
int size;
|
|
size = saveTypeToSize(stype); // int byte
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "size for save=%i",size);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
|
|
sprintf(fname, "/ED64/%s/%s.%s",save_path,rom_name,saveTypeToExtension(stype,ext_type));
|
|
|
|
FatRecord rec_tmpf;
|
|
found = fatFindRecord(fname, &rec_tmpf, 0);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "found=%i",found);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
u8 resp=0;
|
|
|
|
//FAT_ERR_NOT_EXIST 100
|
|
if(found!=0){
|
|
//create before save
|
|
printText("try fatCreateRecIfNotExist", 3, -1, disp);
|
|
resp = fatCreateRecIfNotExist(fname, 0);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatCreateRecIfNotExist ret=%i",resp); //0 means try to create
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
}
|
|
|
|
//open file with stype size
|
|
resp = fatOpenFileByeName(fname, size / 512);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "fatOpenFileByeName ret=%i",resp); //100 not exist
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
//for savegame
|
|
uint8_t cartsave_data[size];
|
|
|
|
for(int zero=0; zero<size;zero++)
|
|
cartsave_data[zero]=0;
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "cartsave_data=%p",&cartsave_data);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
//universal dumpfunction
|
|
//returns data from fpga/cart to save on sd
|
|
|
|
if(getSaveFromCart(stype, cartsave_data)) {
|
|
printText("got save from fpga", 3, -1, disp);
|
|
//write to file
|
|
|
|
if(gb_load_y!=1)
|
|
fatWriteFile(&cartsave_data, size / 512);
|
|
|
|
printText("reset-save done...", 3, -1, disp);
|
|
sleep(3000);
|
|
return 1;
|
|
}
|
|
else {
|
|
printText("getSaveFromCart error", 3, -1, disp);
|
|
sleep(3000);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
//check out the userfriendly ini file for config-information
|
|
|
|
int readConfigFile(void){
|
|
//var file readin
|
|
u8 tmp[32];
|
|
u8 filename[32];
|
|
u8 ok=0;
|
|
|
|
//config filename
|
|
sprintf(filename, "/ED64/ALT64.INI");
|
|
FatRecord rec_tmpf;
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(filename, 0);
|
|
|
|
//filesize of the opend file -> is the readfile / 512
|
|
int fsize= file.sec_available*512;
|
|
char config_rawdata[fsize];
|
|
|
|
resp = fatReadFile(&config_rawdata, fsize / 512); //1 cluster
|
|
configuration config;
|
|
|
|
if (ini_parse_str(config_rawdata, configHandler, &config) < 0) {
|
|
return 0;
|
|
}
|
|
else {
|
|
border_color_1_s=config.border_color_1;
|
|
border_color_2_s=config.border_color_2;
|
|
box_color_s=config.box_color;
|
|
selection_color_s=config.selection_color;
|
|
selection_font_color_s=config.selection_font_color;
|
|
list_font_color_s=config.list_font_color;
|
|
list_dir_font_color_s=config.list_dir_font_color;
|
|
|
|
mempak_path=config.mempak_path;
|
|
save_path=config.save_path;
|
|
sound_on=config.sound_on;
|
|
page_display=config.page_display;
|
|
tv_mode=config.tv_mode;
|
|
quick_boot=config.quick_boot;
|
|
enable_colored_list=config.enable_colored_list;
|
|
ext_type=config.ext_type;
|
|
cd_behaviour=config.cd_behaviour;
|
|
scroll_behaviour=config.scroll_behaviour;
|
|
text_offset=config.text_offset;
|
|
hide_sysfolder=config.hide_sysfolder;
|
|
sd_speed=config.sd_speed;
|
|
background_image=config.background_image;
|
|
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
int str2int(char data){
|
|
data -= '0';
|
|
if (data>9)
|
|
data-= 7;
|
|
|
|
return data;
|
|
}
|
|
|
|
uint32_t translate_color(char *hexstring){
|
|
int r = str2int(hexstring[0])*16 + str2int(hexstring[1]);
|
|
int g = str2int(hexstring[2])*16 + str2int(hexstring[3]);
|
|
int b = str2int(hexstring[4])*16 + str2int(hexstring[5]);
|
|
int a = str2int(hexstring[6])*16 + str2int(hexstring[7]);
|
|
|
|
return graphics_make_color(r,g,b,a);
|
|
}
|
|
|
|
//init fat filesystem after everdrive init and before sdcard access
|
|
void initFilesystem(void){
|
|
sleep(1000);
|
|
evd_ulockRegs();
|
|
sleep(1000);
|
|
|
|
fatInitRam();
|
|
fatInit();
|
|
fat_initialized=1;
|
|
}
|
|
|
|
//prints the sdcard-filesystem content
|
|
void readSDcard(display_context_t disp, char *directory){
|
|
//todo: check out the minimal sleeping needs
|
|
//color test
|
|
|
|
FatRecord *frec;
|
|
u8 cresp = 0;
|
|
count = 1;
|
|
|
|
//load the directory-entry
|
|
cresp = fatLoadDirByName("/ED64/CFG");
|
|
|
|
int dsize=dir->size;
|
|
char colorlist[dsize][256];
|
|
|
|
if(enable_colored_list){
|
|
for (int i = 0; i < dir->size; i++){
|
|
frec = dir->rec[i];
|
|
u8 rom_cfg_file[128];
|
|
|
|
//set rom_cfg
|
|
sprintf(rom_cfg_file, "/ED64/CFG/%s",frec->name );
|
|
|
|
static uint8_t cfg_file_data[512] = { 0 };
|
|
cresp = fatOpenFileByeName(rom_cfg_file, 0); //512 bytes fix one cluster
|
|
cresp = fatReadFile(&cfg_file_data, 1);
|
|
|
|
colorlist[i][0]=(char)cfg_file_data[5]; //color
|
|
strcpy(colorlist[i]+1, cfg_file_data+32); //fullpath
|
|
}
|
|
}
|
|
|
|
|
|
clearScreen(disp);
|
|
printText("SD-Card loading...", 3, 4, disp); //very short display time maybe comment out
|
|
|
|
u8 buff[32];
|
|
|
|
//some trash buffer
|
|
FatRecord *rec;
|
|
u8 resp = 0;
|
|
|
|
count = 1;
|
|
dir_t buf;
|
|
|
|
//load the directory-entry
|
|
resp = fatLoadDirByName(directory);
|
|
|
|
if (resp!=0){
|
|
char error_msg[32];
|
|
sprintf(error_msg,"CHDIR ERROR: %i", resp);
|
|
printText(error_msg, 3, -1, disp);
|
|
sleep(3000);
|
|
}
|
|
|
|
|
|
//clear screen and print the directory name
|
|
clearScreen(disp);
|
|
|
|
//creates string list of files and directorys
|
|
for (int i = 0; i < dir->size; i++) {
|
|
char name_tmpl[32];
|
|
rec = dir->rec[i];
|
|
|
|
if(strcmp(rec->name,"ED64")==0 && hide_sysfolder==1){
|
|
//don't add
|
|
}
|
|
else{
|
|
if(rec->is_dir){
|
|
list[count-1].type = DT_DIR; //2 is dir +1
|
|
}
|
|
else{
|
|
list[count-1].type = DT_REG; //1 is file +1
|
|
}
|
|
|
|
strcpy(list[count-1].filename, rec->name); //+1
|
|
|
|
//new color test
|
|
list[count-1].color = 0;
|
|
|
|
if(enable_colored_list){
|
|
for(int c=0; c<dsize; c++){
|
|
|
|
u8 short_name[256];
|
|
|
|
sprintf(short_name, "%s", colorlist[c]+1);
|
|
|
|
u8 * pch_s; // point-offset
|
|
pch_s=strrchr(short_name,'/');
|
|
|
|
if(strcmp(list[count-1].filename, pch_s+1)==0){
|
|
|
|
list[count-1].color = colorlist[c][0];
|
|
|
|
}
|
|
}
|
|
//new color test end
|
|
}
|
|
|
|
count++;
|
|
list = realloc(list, sizeof(direntry_t) * count);
|
|
}
|
|
}
|
|
count--;
|
|
|
|
page = 0;
|
|
cursor = 0;
|
|
select_mode=1;
|
|
|
|
if(count > 0) {
|
|
/* Should sort! */
|
|
qsort(list, count, sizeof(direntry_t), compare);
|
|
}
|
|
|
|
//print directory
|
|
display_dir(list, cursor, page, MAX_LIST, count, disp);
|
|
}
|
|
|
|
//void readCheatFile(char *filename, display_context_t disp){
|
|
int readCheatFile(char *filename){
|
|
//var file readin
|
|
u8 tmp[32];
|
|
u8 ok=0;
|
|
u8 firstr=1;
|
|
|
|
char *cp, *vp, *dp;
|
|
char buffer[512];
|
|
char temp[42];
|
|
char buff[512];
|
|
|
|
int i = 0, j, type, offset = 0;
|
|
|
|
int curr_cheat = -1;
|
|
|
|
FatRecord rec_tmpf;
|
|
ok = fatFindRecord(filename, &rec_tmpf, 0);
|
|
|
|
if(ok!=0){
|
|
return -1; //err file not found
|
|
}
|
|
else{
|
|
u8 resp = 0;
|
|
resp = fatOpenFileByeName(filename, 0);
|
|
|
|
//filesize of the opend file -> is the readfile / 512
|
|
int fsize= file.sec_available*512;
|
|
char cheatfile_rawdata[fsize];
|
|
|
|
resp = fatReadFile(&cheatfile_rawdata, fsize / 512); //1 cluster
|
|
|
|
int line_chr=0;
|
|
long c=0;
|
|
|
|
for(c=0;c<fsize;c++){
|
|
buff[line_chr++]=cheatfile_rawdata[c];
|
|
|
|
if(cheatfile_rawdata[c]=='\n'){
|
|
i = 0;
|
|
|
|
// process GameShark Code line
|
|
cp = vp = dp = NULL;
|
|
|
|
while ((buff[i] == ' ') || (buff[i] == '\t'))
|
|
i++; // skip initial whitespace
|
|
|
|
// check for blank line
|
|
if ((buff[i] == '\n') || (buff[i] == '\r')) //carriage return
|
|
{
|
|
line_chr=0;
|
|
continue; // skip
|
|
}
|
|
|
|
if ((buff[i] == '#') || (buff[i] == ';')) {
|
|
line_chr=0;
|
|
continue; // skip
|
|
}
|
|
|
|
cp = &buff[i];
|
|
|
|
while ((buff[i] != ' ') && (buff[i] != '\t') && (buff[i] != '\n') && (buff[i] != '\r'))
|
|
i++;
|
|
|
|
buff[i] = 0;
|
|
i++;
|
|
|
|
while ((buff[i] == ' ') || (buff[i] == '\t'))
|
|
i++; // skip whitespace
|
|
|
|
vp = &buff[i];
|
|
while ((buff[i] != ' ') && (buff[i] != '\t') && (buff[i] != '\n') && (buff[i] != '\r'))
|
|
i++; // find end of GameShark code value
|
|
|
|
if ((buff[i] == ' ') || (buff[i] == '\t')) {
|
|
buff[i] =0;
|
|
i++;
|
|
|
|
while ((buff[i] == ' ') || (buff[i] == '\t'))
|
|
i++; // skip whitespace
|
|
|
|
if ((buff[i] != '\n') && (buff[i] != '\r') && (buff[i] != '#') && (buff[i] != ';')) {
|
|
dp = &buff[i];
|
|
|
|
while ((buff[i] != '\n') && (buff[i] != '\r'))
|
|
i++; // find end of GameShark code description
|
|
|
|
buff[i] =0;
|
|
}
|
|
}
|
|
else {
|
|
buff[i] =0;
|
|
}
|
|
|
|
if (dp) {
|
|
// starting new cheat
|
|
curr_cheat++;
|
|
|
|
gGSCodes[curr_cheat].description= strdup(dp);
|
|
gGSCodes[curr_cheat].gscodes = NULL;
|
|
gGSCodes[curr_cheat].count = 0;
|
|
gGSCodes[curr_cheat].state = 1;
|
|
gGSCodes[curr_cheat].mask = 0;
|
|
|
|
if (!ishexchar(vp[3]))
|
|
gGSCodes[curr_cheat].mask |= 0x000F;
|
|
|
|
if (!ishexchar(vp[2]))
|
|
gGSCodes[curr_cheat].mask |= 0x00F0;
|
|
|
|
if (!ishexchar(vp[1]))
|
|
gGSCodes[curr_cheat].mask |= 0x0F00;
|
|
|
|
if (!ishexchar(vp[0]))
|
|
gGSCodes[curr_cheat].mask |= 0xF000;
|
|
|
|
gGSCodes[curr_cheat].value = 0;
|
|
offset = 0;
|
|
}
|
|
|
|
if (curr_cheat < 0)
|
|
continue; // safety check
|
|
|
|
temp[0] = cp[0];
|
|
temp[1] = cp[1];
|
|
temp[2] = 0;
|
|
type = strtol(temp, (char **)NULL, 16);
|
|
|
|
switch (type) {
|
|
case 0x50:
|
|
// patch codes - unimplemented, also skips next line
|
|
// 5000XXYY 00ZZ
|
|
// TTTTTTTT VVVV
|
|
//skip next line missing
|
|
break;
|
|
|
|
case 0x80:
|
|
// write 8-bit value to (cached) ram continuously
|
|
// 80XXYYYY 00ZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0x81:
|
|
// write 16-bit value to (cached) ram continuously
|
|
// 81XXYYYY ZZZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0x88:
|
|
// write 8-bit value to (cached) ram on GS button pressed - unimplemented
|
|
// 88XXYYYY 00ZZ
|
|
break;
|
|
|
|
case 0x89:
|
|
// write 16-bit value to (cached) ram on GS button pressed - unimplemented
|
|
// 89XXYYYY ZZZZ
|
|
break;
|
|
|
|
case 0xA0:
|
|
// write 8-bit value to (uncached) ram continuously
|
|
// A0XXYYYY 00ZZ => 3C1A A0XX 375A YYYY 241B 00ZZ A35B 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xA1:
|
|
// write 16-bit value to (uncached) ram continuously
|
|
// A1XXYYYY ZZZZ => 3C1A A0XX 375A YYYY 241B ZZZZ A75B 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xCC:
|
|
// deactivate expansion ram using 3rd method
|
|
// CC000000 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xD0:
|
|
// do next gs code if ram location is equal to 8-bit value
|
|
// D0XXYYYY 00ZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xD1:
|
|
// do next gs code if ram location is equal to 16-bit value
|
|
// D1XXYYYY ZZZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xD2:
|
|
// do next gs code if ram location is not equal to 8-bit value
|
|
// D2XXYYYY 00ZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xD3:
|
|
// do next gs code if ram location is not equal to 16-bit value
|
|
// D1XXYYYY ZZZZ
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xDD:
|
|
// deactivate expansion ram using 2nd method
|
|
// DD000000 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xDE:
|
|
// set game boot address
|
|
// DEXXXXXX 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xEE:
|
|
// deactivate expansion ram using 1st method
|
|
// EE000000 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xF0:
|
|
// write 8-bit value to (cached) ram before boot
|
|
// F0XXXXXX 00YY
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xF1:
|
|
// write 16-bit value to (cached) ram before boot
|
|
// F1XXXXXX YYYY
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
|
|
case 0xFF:
|
|
// set code base
|
|
// FFXXXXXX 0000
|
|
if (gGSCodes[curr_cheat].gscodes)
|
|
gGSCodes[curr_cheat].gscodes = realloc(gGSCodes[curr_cheat].gscodes, offset + 16);
|
|
else
|
|
gGSCodes[curr_cheat].gscodes = malloc(16);
|
|
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset], cp, 9);
|
|
memcpy(&gGSCodes[curr_cheat].gscodes[offset+9], vp, 5);
|
|
gGSCodes[curr_cheat].count++;
|
|
offset += 16;
|
|
break;
|
|
}
|
|
|
|
line_chr=0;
|
|
}
|
|
}
|
|
|
|
curr_cheat++;
|
|
gGSCodes[curr_cheat].count = 0xFFFF; // end of table
|
|
gGSCodes[curr_cheat].gscodes = NULL;
|
|
gGSCodes[curr_cheat].state = 0;
|
|
}
|
|
|
|
return 0; //ok
|
|
}
|
|
|
|
void timing(display_context_t disp){
|
|
unsigned char tmp[32];
|
|
|
|
IO_WRITE(PI_STATUS_REG, 0x02);
|
|
|
|
u32 pi0 = IO_READ(PI_BSD_DOM1_LAT_REG);
|
|
u32 pi1 = IO_READ(PI_BSD_DOM1_PWD_REG);
|
|
u32 pi2 = IO_READ(PI_BSD_DOM1_PGS_REG);
|
|
u32 pi3 = IO_READ(PI_BSD_DOM1_RLS_REG);
|
|
|
|
printText("timing dom1:", 3, -1, disp);
|
|
sprintf(tmp, "lat=%x pwd=%x\npgs=%x rls=%x",pi0,pi1,pi2,pi3);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
|
|
void bootRom(display_context_t disp, int silent){
|
|
if(boot_cic!=0){
|
|
if(boot_save!=0){
|
|
u8 cfg_file[32];
|
|
u8 found=0;
|
|
u8 resp=0;
|
|
u8 tmp[32];
|
|
|
|
//set cfg file with last loaded cart info and save-type
|
|
sprintf(cfg_file, "/ED64/%s/LAST.CRT",save_path);
|
|
|
|
resp = fatCreateRecIfNotExist(cfg_file, 0);
|
|
resp = fatOpenFileByeName(cfg_file, 1); //512 bytes fix one cluster
|
|
|
|
static uint8_t cfg_file_data[512] = { 0 };
|
|
cfg_file_data[0]=boot_save;
|
|
cfg_file_data[1]=boot_cic;
|
|
scopy(rom_filename, cfg_file_data+2);
|
|
|
|
fatWriteFile(&cfg_file_data, 1);
|
|
|
|
sleep(500);
|
|
//set the fpga cart-save tpye
|
|
|
|
evd_setSaveType(boot_save);
|
|
|
|
if (debug) printText("try to restore save from sd", 3, -1, disp);
|
|
resp = saveTypeFromSd(disp, rom_filename, boot_save);
|
|
|
|
if (debug) {
|
|
sprintf(tmp, "saveTypeFromSd ret=%i",resp);
|
|
printText(tmp, 3, -1, disp);
|
|
}
|
|
}
|
|
|
|
if (debug) {
|
|
printText("Cartridge-Savetype set", 3, -1, disp);
|
|
printText("information stored for reboot-save...", 3, -1, disp);
|
|
}
|
|
|
|
sleep(50);
|
|
|
|
u32 cart, country;
|
|
u32 info = *(vu32 *)0xB000003C;
|
|
cart = info >> 16;
|
|
country = (info >> 8) & 0xFF;
|
|
|
|
if(cheats_on){
|
|
gCheats=1;
|
|
printText("try to load cheat-file...", 3, -1, disp);
|
|
|
|
char cheat_filename[64];
|
|
sprintf(cheat_filename,"/ED64/CHEATS/%s.cht",rom_filename);
|
|
|
|
int ok = readCheatFile(cheat_filename);
|
|
if(ok==0) {
|
|
if(!silent)
|
|
printText("cheats found...", 3, -1, disp);
|
|
|
|
sleep(600);
|
|
}
|
|
else {
|
|
if(!silent)
|
|
printText("cheats not found...", 3, -1, disp);
|
|
|
|
gCheats=0;
|
|
sleep(2000);
|
|
}
|
|
}
|
|
else {
|
|
gCheats=0;
|
|
}
|
|
|
|
disable_interrupts();
|
|
if(!silent){
|
|
if(gCheats)
|
|
printText("cheat boot", 3, -1, disp);
|
|
else
|
|
printText("normal boot", 3, -1, disp);
|
|
}
|
|
int bios_cic=getCicType(1);
|
|
|
|
if(checksum_fix_on)
|
|
checksum_sdram();
|
|
|
|
evd_lockRegs();
|
|
sleep(1000);
|
|
|
|
while( !(disp = display_lock()) );
|
|
//blank screen to avoid glitches
|
|
|
|
graphics_fill_screen(disp, 0x000000FF);
|
|
display_show(disp);
|
|
|
|
simulate_boot(boot_cic, bios_cic); // boot_cic
|
|
}
|
|
}
|
|
|
|
void playSound(int snd){
|
|
//no thread support in libdragon yet, sounds pause the menu for a time :/
|
|
|
|
//maybe global
|
|
int v1;
|
|
|
|
static SAMPLE *add_sfx = NULL;
|
|
if(snd==1)
|
|
add_sfx = Sample_Load("rom://ed64_mono.wav");
|
|
|
|
if(snd==2)
|
|
add_sfx = Sample_Load("rom://bamboo.wav");
|
|
|
|
if(snd==3)
|
|
add_sfx = Sample_Load("rom://warning.wav");
|
|
|
|
if(snd==4)
|
|
add_sfx = Sample_Load("rom://done.wav");
|
|
|
|
MikMod_SetNumVoices(-1, 2);
|
|
|
|
if (!add_sfx) {
|
|
MikMod_Exit();
|
|
}
|
|
else{
|
|
MikMod_EnableOutput();
|
|
|
|
audio_write_silence();
|
|
audio_write_silence();
|
|
|
|
v1 = Sample_Play(add_sfx, 0, 0);
|
|
Voice_SetVolume(v1, 100);
|
|
|
|
//maybe put update function into a int/vblank callback
|
|
for(int s=0;s<50;s++){
|
|
MikMod_Update();
|
|
sleep(10);
|
|
}
|
|
|
|
MikMod_DisableOutput();
|
|
Sample_Free(add_sfx);
|
|
}
|
|
}
|
|