274 lines
8.4 KiB
C
274 lines
8.4 KiB
C
/* sd2snes - SD card based universal cartridge for the SNES
|
|
Copyright (C) 2009-2010 Maximilian Rehkopf <otakon@gmx.net>
|
|
AVR firmware portion
|
|
|
|
Inspired by and based on code from sd2iec, written by Ingo Korb et al.
|
|
See sdcard.c|h, config.h.
|
|
|
|
FAT file system access based on code by ChaN, Jim Brain, Ingo Korb,
|
|
see ff.c|h.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License only.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
filetypes.c: directory scanning and file type detection
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <avr/pgmspace.h>
|
|
#include <util/delay.h>
|
|
#include "config.h"
|
|
#include "uart.h"
|
|
#include "filetypes.h"
|
|
#include "ff.h"
|
|
#include "smc.h"
|
|
#include "fileops.h"
|
|
#include "crc16.h"
|
|
#include "memory.h"
|
|
#include "led.h"
|
|
|
|
uint16_t scan_flat(const char* path) {
|
|
DIR dir;
|
|
FRESULT res;
|
|
FILINFO fno;
|
|
fno.lfn = NULL;
|
|
res = f_opendir(&dir, (unsigned char*)path);
|
|
uint16_t numentries = 0;
|
|
if (res == FR_OK) {
|
|
for (;;) {
|
|
res = f_readdir(&dir, &fno);
|
|
if(res != FR_OK || fno.fname[0] == 0)break;
|
|
numentries++;
|
|
}
|
|
}
|
|
return numentries;
|
|
}
|
|
|
|
uint16_t scan_dir(char* path, char mkdb, uint32_t this_dir_tgt) {
|
|
DIR dir;
|
|
FILINFO fno;
|
|
FRESULT res;
|
|
uint8_t len;
|
|
unsigned char* fn;
|
|
static unsigned char depth = 0;
|
|
static uint16_t crc;
|
|
static uint32_t db_tgt;
|
|
static uint32_t next_subdir_tgt;
|
|
static uint32_t parent_tgt;
|
|
static uint32_t dir_end = 0;
|
|
static uint8_t was_empty = 0;
|
|
uint32_t dir_tgt;
|
|
uint16_t numentries;
|
|
uint32_t dirsize;
|
|
uint8_t pass = 0;
|
|
|
|
dir_tgt = this_dir_tgt;
|
|
if(depth==0) {
|
|
crc = 0;
|
|
db_tgt = SRAM_DB_ADDR+0x10;
|
|
dir_tgt = SRAM_DIR_ADDR;
|
|
next_subdir_tgt = SRAM_DIR_ADDR;
|
|
this_dir_tgt = SRAM_DIR_ADDR;
|
|
parent_tgt = 0;
|
|
dprintf("root dir @%lx\n", dir_tgt);
|
|
}
|
|
|
|
fno.lfn = file_lfn;
|
|
numentries=0;
|
|
for(pass = 0; pass < 2; pass++) {
|
|
if(pass) {
|
|
dirsize = 4*(numentries);
|
|
// dir_tgt_next = dir_tgt + dirsize + 4; // number of entries + end marker
|
|
next_subdir_tgt += dirsize + 4;
|
|
if(parent_tgt) next_subdir_tgt += 4;
|
|
if(next_subdir_tgt > dir_end) {
|
|
dir_end = next_subdir_tgt;
|
|
}
|
|
dprintf("path=%s depth=%d ptr=%lx entries=%d parent=%lx next subdir @%lx\n", path, depth, db_tgt, numentries, parent_tgt, next_subdir_tgt /*dir_tgt_next*/);
|
|
// _delay_ms(50);
|
|
if(mkdb) {
|
|
dprintf("d=%d Saving %lX to Address %lX [end]\n", depth, 0L, next_subdir_tgt - 4);
|
|
// _delay_ms(50);
|
|
sram_writelong(0L, next_subdir_tgt - 4);
|
|
}
|
|
}
|
|
res = f_opendir(&dir, (unsigned char*)path);
|
|
if (res == FR_OK) {
|
|
if(pass && parent_tgt && mkdb) {
|
|
// write backlink to parent dir
|
|
// switch to next bank if record does not fit in current bank
|
|
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt)+sizeof(len)+4))&0xffff)) {
|
|
dprintf("switch! old=%lx ", db_tgt);
|
|
db_tgt &= 0xffff0000;
|
|
db_tgt += 0x00010000;
|
|
dprintf("new=%lx\n", db_tgt);
|
|
}
|
|
sram_writelong((parent_tgt-SRAM_MENU_ADDR), db_tgt);
|
|
sram_writebyte(0, db_tgt+sizeof(next_subdir_tgt));
|
|
sram_writeblock("../\0", db_tgt+sizeof(next_subdir_tgt)+sizeof(len), 4);
|
|
sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
|
|
db_tgt += sizeof(next_subdir_tgt)+sizeof(len)+4;
|
|
dir_tgt += 4;
|
|
}
|
|
len = strlen((char*)path);
|
|
for (;;) {
|
|
toggle_busy_led();
|
|
res = f_readdir(&dir, &fno);
|
|
if (res != FR_OK || fno.fname[0] == 0) {
|
|
if(pass) {
|
|
if(!numentries) was_empty=1;
|
|
}
|
|
break;
|
|
}
|
|
fn = *fno.lfn ? fno.lfn : fno.fname;
|
|
// dprintf("%s\n", fn);
|
|
// _delay_ms(100);
|
|
if (*fn == '.') continue;
|
|
if (fno.fattrib & AM_DIR) {
|
|
numentries++;
|
|
if(pass) {
|
|
path[len]='/';
|
|
strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
|
|
depth++;
|
|
if(mkdb) {
|
|
uint16_t pathlen = strlen(path);
|
|
// write element pointer to current dir structure
|
|
dprintf("d=%d Saving %lX to Address %lX [dir]\n", depth, db_tgt, dir_tgt);
|
|
// _delay_ms(50);
|
|
sram_writelong((db_tgt-SRAM_MENU_ADDR)|((uint32_t)0x80<<24), dir_tgt);
|
|
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt_save, sizeof(dir_tgt_save));
|
|
|
|
// save element:
|
|
// - path name
|
|
// - pointer to sub dir structure
|
|
if((db_tgt&0xffff) > ((0x10000-(sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2))&0xffff)) {
|
|
dprintf("switch! old=%lx ", db_tgt);
|
|
db_tgt &= 0xffff0000;
|
|
db_tgt += 0x00010000;
|
|
dprintf("new=%lx\n", db_tgt);
|
|
}
|
|
dprintf(" Saving dir descriptor to %lX, tgt=%lX, path=%s\n", db_tgt, next_subdir_tgt, path);
|
|
// _delay_ms(100);
|
|
sram_writelong((next_subdir_tgt-SRAM_MENU_ADDR), db_tgt);
|
|
sram_writebyte(len+1, db_tgt+sizeof(next_subdir_tgt));
|
|
sram_writeblock(path, db_tgt+sizeof(next_subdir_tgt)+sizeof(len), pathlen);
|
|
sram_writeblock("/\0", db_tgt + sizeof(next_subdir_tgt) + sizeof(len) + pathlen, 2);
|
|
// sram_writeblock((uint8_t*)&dir_tgt, db_tgt+256, sizeof(dir_tgt));
|
|
db_tgt += sizeof(next_subdir_tgt) + sizeof(len) + pathlen + 2;
|
|
}
|
|
parent_tgt = this_dir_tgt;
|
|
scan_dir(path, mkdb, next_subdir_tgt);
|
|
dir_tgt += 4;
|
|
// if(was_empty)dir_tgt_next += 4;
|
|
was_empty = 0;
|
|
depth--;
|
|
path[len]=0;
|
|
}
|
|
} else {
|
|
SNES_FTYPE type = determine_filetype((char*)fn);
|
|
if(type != TYPE_UNKNOWN) {
|
|
numentries++;
|
|
if(pass) {
|
|
if(mkdb) {
|
|
snes_romprops_t romprops;
|
|
path[len]='/';
|
|
strncpy(path+len+1, (char*)fn, sizeof(fs_path)-len);
|
|
uint16_t pathlen = strlen(path);
|
|
switch(type) {
|
|
case TYPE_SMC:
|
|
// XXX file_open_by_filinfo(&fno);
|
|
// XXX if(file_res){
|
|
// XXX dprintf("ZOMG NOOOO %d\n", file_res);
|
|
// XXX _delay_ms(30);
|
|
// XXX }
|
|
// XXX smc_id(&romprops);
|
|
// XXX file_close();
|
|
// _delay_ms(30);
|
|
// write element pointer to current dir structure
|
|
// dprintf("d=%d Saving %lX to Address %lX [file]\n", depth, db_tgt, dir_tgt);
|
|
// _delay_ms(50);
|
|
if((db_tgt&0xffff) > ((0x10000-(sizeof(romprops) + sizeof(len) + pathlen + 1))&0xffff)) {
|
|
dprintf("switch! old=%lx ", db_tgt);
|
|
db_tgt &= 0xffff0000;
|
|
db_tgt += 0x00010000;
|
|
dprintf("new=%lx\n", db_tgt);
|
|
}
|
|
sram_writelong((db_tgt-SRAM_MENU_ADDR), dir_tgt);
|
|
// sram_writeblock((uint8_t*)&db_tgt, dir_tgt, sizeof(db_tgt));
|
|
dir_tgt += 4;
|
|
// save element:
|
|
// - SNES header information
|
|
// - file name
|
|
sram_writeblock((uint8_t*)&romprops, db_tgt, sizeof(romprops));
|
|
sram_writebyte(len+1, db_tgt + sizeof(romprops));
|
|
sram_writeblock(path, db_tgt + sizeof(romprops) + sizeof(len), pathlen + 1);
|
|
db_tgt += sizeof(romprops) + sizeof(len) + pathlen + 1;
|
|
break;
|
|
case TYPE_UNKNOWN:
|
|
default:
|
|
break;
|
|
}
|
|
path[len]=0;
|
|
// dprintf("%s ", path);
|
|
// _delay_ms(30);
|
|
}
|
|
} else {
|
|
unsigned char* sfn = fno.fname;
|
|
while(*sfn != 0) {
|
|
crc += crc16_update(crc, sfn++, 1);
|
|
}
|
|
}
|
|
}
|
|
// dprintf("%s/%s\n", path, fn);
|
|
// _delay_ms(50);
|
|
}
|
|
}
|
|
} else uart_putc(0x30+res);
|
|
}
|
|
// dprintf("%x\n", crc);
|
|
// _delay_ms(50);
|
|
sram_writelong(db_tgt, SRAM_DB_ADDR+4);
|
|
sram_writelong(dir_end, SRAM_DB_ADDR+8);
|
|
return crc;
|
|
}
|
|
|
|
|
|
SNES_FTYPE determine_filetype(char* filename) {
|
|
char* ext = strrchr(filename, '.');
|
|
if(ext == NULL)
|
|
return TYPE_UNKNOWN;
|
|
if(!strcasecmp_P(ext+1, PSTR("SMC"))) {
|
|
return TYPE_SMC;
|
|
}/* later
|
|
if(!strcasecmp_P(ext+1, PSTR("SRM"))) {
|
|
return TYPE_SRM;
|
|
}
|
|
if(!strcasecmp_P(ext+1, PSTR("SPC"))) {
|
|
return TYPE_SPC;
|
|
}*/
|
|
return TYPE_UNKNOWN;
|
|
}
|
|
|
|
FRESULT get_db_id(uint16_t* id) {
|
|
file_open((uint8_t*)"/sd2snes/sd2snes.db", FA_READ);
|
|
if(file_res == FR_OK) {
|
|
file_readblock(id, 0, 2);
|
|
/* XXX */// *id=0xdead;
|
|
file_close();
|
|
} else {
|
|
*id=0xdead;
|
|
}
|
|
return file_res;
|
|
}
|