19 Commits
progmem ... mmc

Author SHA1 Message Date
optixx
23efb8da74 change project 2009-08-24 20:27:28 +02:00
David Voswinkel
dade0ea275 add test dir loop 2009-08-18 09:11:07 +02:00
David Voswinkel
6edd54b092 switch file id to 32bit and get sram push working 2009-08-18 08:38:48 +02:00
David Voswinkel
dc8ed94279 add dir entry debug dump 2009-08-17 22:05:05 +02:00
David Voswinkel
7046230e31 push dir entry to sram 2009-08-17 21:44:38 +02:00
David Voswinkel
ed0a95cad5 fix file_entry struct 2009-08-17 20:39:38 +02:00
David Voswinkel
31768e2a41 Merge branch 'mmc' of git@github.com:optixx/quickdev16 into mmc 2009-08-12 21:19:18 +02:00
optixx
041cf089ad add header 2009-08-12 18:04:54 +02:00
optixx
cf090451df add dir ent to sram copy 2009-08-11 15:42:14 +02:00
David Voswinkel
51876b83ad cleanup 2009-08-10 19:46:45 +02:00
David Voswinkel
8d961dc446 Merge branch 'mmc' of git@github.com:optixx/quickdev16 into mmc
Conflicts:
	avr/usbload/fat.h
	avr/usbload/file.c
	avr/usbload/testing.c
2009-08-10 19:44:15 +02:00
David Voswinkel
9859b1fbc8 cleanup types: 2009-08-10 19:34:03 +02:00
David Voswinkel
8656beb769 code cleanup 2009-08-10 19:26:01 +02:00
optixx
f1f836bdc7 disable file write function and save 4kb progmem 2009-08-10 16:29:36 +02:00
David Voswinkel
4a0740dd02 replace mmc layer with old software spi stuff 2009-08-09 14:19:32 +02:00
David Voswinkel
d095867fe4 try to use irq for CS and use dedicated SS for hardware SPI 2009-08-09 13:12:44 +02:00
David Voswinkel
2aee210d13 switch to mmc-0.5.4 2009-08-09 12:15:06 +02:00
David Voswinkel
a27521b22b first tests 2009-08-09 10:37:51 +02:00
David Voswinkel
2132b572ff add mmc layer 2009-08-08 16:43:51 +02:00
643 changed files with 25211 additions and 38948 deletions

9
.gitignore vendored
View File

@@ -27,12 +27,3 @@
*.vfat *.vfat
*.wla* *.wla*
*.rcc *.rcc
*.log
bootloader
snesuploader
tmtags
bsnes
web
ucon64.exe

8
README
View File

@@ -1,8 +0,0 @@
________ .__ __ ________ ____ ________
\_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
/ / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
/ \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
\_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
\__> \/ \/ \/ \/ \/
www.optixx.org

View File

@@ -67,7 +67,7 @@ clean:
.PHONY: all clean interactive-isp interactive-serial launch-bootloader .PHONY: all clean interactive-isp interactive-serial launch-bootloader
flash: bootloader.hex flash:
$(AVRDUDE) $(AVRDUDE_FLAGS) -c $(ISP_PROG) -U flash:w:$< $(AVRDUDE) $(AVRDUDE_FLAGS) -c $(ISP_PROG) -U flash:w:$<
flash-eeprom-%: %.eep.hex flash-eeprom-%: %.eep.hex

View File

@@ -286,7 +286,7 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
boot_page_erase(flash_address.word); boot_page_erase(flash_address.word);
sei(); sei();
} }
uart_puts("\n\rWrite Flash"); uart_puts("\n\r");
} }
/* /*
@@ -406,10 +406,9 @@ void leave_bootloader(void)
* disconnect usb * disconnect usb
*/ */
usbDeviceDisconnect(); usbDeviceDisconnect();
#if 0
for (uint8_t i = 0; i < 50; i++) for (uint8_t i = 0; i < 50; i++)
_delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */ _delay_ms(10); /* 0 means 0x10000, 38*1/f*0x10000 =~ 498ms */
#endif
/* /*
* enable watchdog to soft-reset the uC for clean startup of new application * enable watchdog to soft-reset the uC for clean startup of new application
*/ */
@@ -422,13 +421,6 @@ void leave_bootloader(void)
} }
void banner(){
uart_puts("\n\r");
uart_puts("\n\r");
uart_puts("\n\r");
uart_puts("Quickdev16 Bootloader v0.2\n\r");
uart_puts("www.optixx.org\n\r");
}
int __attribute__ ((noreturn, OS_main)) main(void) int __attribute__ ((noreturn, OS_main)) main(void)
{ {
@@ -449,12 +441,12 @@ int __attribute__ ((noreturn, OS_main)) main(void)
uint16_t delay = 0; uint16_t delay = 0;
timeout = TIMEOUT; timeout = TIMEOUT;
uart_puts("Snesram Bootloader v0.1\n\r");
/* /*
* if power-on reset, quit bootloader via watchdog reset * if power-on reset, quit bootloader via watchdog reset
*/ */
if (reset & _BV(PORF)) { if (reset & _BV(PORF)) {
banner();
uart_puts("Found power on reset\n\r"); uart_puts("Found power on reset\n\r");
MCUSR = 0; MCUSR = 0;
leave_bootloader(); leave_bootloader();
@@ -466,11 +458,15 @@ int __attribute__ ((noreturn, OS_main)) main(void)
uart_puts("Found watchdog reset\n\r"); uart_puts("Found watchdog reset\n\r");
MCUSR = 0; MCUSR = 0;
wdt_disable(); wdt_disable();
uart_puts("Jump to 0x0000\n\r"); DLED_TGL;
_delay_ms(500);
DLED_TGL;
_delay_ms(500);
uart_puts("Jump to main\n\r");
jump_to_app(); jump_to_app();
} }
banner();
uart_puts("Enter programming mode\n\r"); uart_puts("Enter programming mode\n\r");
/* /*
* else: enter programming mode * else: enter programming mode

View File

@@ -33,13 +33,13 @@ ifeq ($(DEBUG),1)
OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o \ OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o \
main.o usb_bulk.o uart.o fifo.o sram.o crc.o debug.o \ main.o usb_bulk.o uart.o fifo.o sram.o crc.o debug.o \
dump.o timer.o watchdog.o rle.c loader.o info.o shared_memory.o \ dump.o timer.o watchdog.o rle.c loader.o info.o shared_memory.o \
irq.o command.o testing.o command.o mmc.o fat.o file.o dir.o testing.o
else else
LDFLAGS = -Wl,-u LDFLAGS = -Wl,-u
CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 -DNO_DEBUG -DNO_INFO CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0 -DNO_DEBUG -DNO_INFO
OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o usb_bulk.o \ OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o usb_bulk.o \
uart.o fifo.o sram.o crc.o debug.o dump.o timer.o watchdog.o rle.c loader.o \ uart.o fifo.o sram.o crc.o debug.o dump.o timer.o watchdog.o rle.c loader.o \
info.o shared_memory.o command.o irq.o info.o shared_memory.o command.o
endif endif
COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE)
@@ -62,8 +62,11 @@ help:
@echo "make clean ..... to delete objects and hex file" @echo "make clean ..... to delete objects and hex file"
hex: main.hex hex: main.hex
@echo "==============================="
@echo "$(TARGET) compiled for: $(DEVICE)" @echo "$(TARGET) compiled for: $(DEVICE)"
@./checksize $(TARGET).elf @echo -n "size is: "
@$(SIZE) -A $(TARGET).hex | grep "\.sec1" | tr -s " " | cut -d" " -f2
@echo "==============================="
program: flash fuse program: flash fuse

6
avr/usbload/checksize Executable file → Normal file
View File

@@ -5,11 +5,11 @@
# Creation Date: 2004-12-29 # Creation Date: 2004-12-29
# Tabsize: 4 # Tabsize: 4
# Copyright: (c) 2005 OBJECTIVE DEVELOPMENT Software GmbH. # Copyright: (c) 2005 OBJECTIVE DEVELOPMENT Software GmbH.
# Revision: $:Id: checksize 83 2006-01-05 22:20:53Z cs $ # Revision: $Id: checksize 83 2006-01-05 22:20:53Z cs $
error=0 error=0
codelimit=65536 # default value codelimit=16384 # default value
datalimit=4064 # default value; leave 32 bytes for stack datalimit=992 # default value; leave 32 bytes for stack
if [ $# -gt 1 ]; then if [ $# -gt 1 ]; then
codelimit="$2" codelimit="$2"

View File

@@ -19,7 +19,6 @@
*/ */
#include <avr/io.h> #include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h> #include <util/delay.h>
#include <stdlib.h> #include <stdlib.h>
@@ -27,21 +26,18 @@
#include "requests.h" #include "requests.h"
#include "sram.h" #include "sram.h"
#include "info.h" #include "info.h"
#include "irq.h"
extern uint32_t req_bank_size; extern uint32_t req_bank_size;
void send_reset() void send_reset()
{ {
info_P(PSTR("Reset SNES\n")); info("Reset Snes\n");
cli();
snes_reset_on(); snes_reset_on();
snes_reset_lo(); snes_reset_lo();
_delay_ms(2); _delay_ms(2);
snes_reset_hi(); snes_reset_hi();
snes_reset_off(); snes_reset_off();
sei();
} }
void send_irq() void send_irq()
@@ -57,9 +53,9 @@ void set_rom_mode()
{ {
if (req_bank_size == 0x8000) { if (req_bank_size == 0x8000) {
snes_lorom(); snes_lorom();
info_P(PSTR("Set SNES lowrom \n")); info("Set Snes lowrom \n");
} else { } else {
snes_hirom(); snes_hirom();
info_P(PSTR("Set SNES hirom \n")); info("Set Snes hirom \n");
} }
} }

View File

@@ -27,7 +27,7 @@
#define DEBUG_USB_TRANS 4 #define DEBUG_USB_TRANS 4
#define DEBUG_SRAM 8 #define DEBUG_SRAM 8
#define DEBUG_SRAM_RAW 16 #define DEBUG_SRAM_RAW 16
#define DEBUG_SREG 32 #define DEBUG_FAT 32
#define DEBUG_CRC 64 #define DEBUG_CRC 64
#define DEBUG_SHM 128 #define DEBUG_SHM 128
@@ -43,8 +43,6 @@
#define USB_CRC_CHECK 0x01 #define USB_CRC_CHECK 0x01
#define TRANSFER_BUFFER_SIZE 0x200 #define TRANSFER_BUFFER_SIZE 0x200
#define FORMAT_BUFFER_LEN 0x0FF
#define HW_VERSION "2.6"
#define SW_VERSION "1.0"
#endif #endif

View File

@@ -71,12 +71,10 @@ uint16_t crc_check_bulk_memory(uint32_t bottom_addr, uint32_t top_addr, uint32_t
uint32_t addr = 0; uint32_t addr = 0;
uint8_t req_bank = 0; uint8_t req_bank = 0;
sram_bulk_read_start(bottom_addr); sram_bulk_read_start(bottom_addr);
debug_P(DEBUG_CRC, PSTR("crc_check_bulk_memory: bottom_addr=0x%08lx top_addr=0x%08lx\n"),
bottom_addr,top_addr);
for (addr = bottom_addr; addr < top_addr; addr++) { for (addr = bottom_addr; addr < top_addr; addr++) {
if (addr && addr % bank_size == 0) { if (addr && addr % bank_size == 0) {
debug_P(DEBUG_CRC, PSTR("crc_check_bulk_memory: bank=0x%02x addr=0x%08lx crc=0x%04x\n"), debug(DEBUG_CRC,"crc_check_bulk_memory: bank=0x%02x addr=0x%08lx crc=0x%04x\n",
req_bank,addr,crc); req_bank,addr,crc);
req_bank++; req_bank++;
crc = 0; crc = 0;
@@ -85,7 +83,7 @@ uint16_t crc_check_bulk_memory(uint32_t bottom_addr, uint32_t top_addr, uint32_t
sram_bulk_read_next(); sram_bulk_read_next();
} }
if (addr % 0x8000 == 0) if (addr % 0x8000 == 0)
debug_P(DEBUG_CRC, PSTR("crc_check_bulk_memory: bank=0x%02x addr=0x%08lx crc=0x%04x\n"), debug(DEBUG_CRC,"crc_check_bulk_memory: bank=0x%02x addr=0x%08lx crc=0x%04x\n",
req_bank,addr,crc); req_bank,addr,crc);
sram_bulk_read_end(); sram_bulk_read_end();
return crc; return crc;
@@ -99,7 +97,7 @@ uint16_t crc_check_memory_range(uint32_t start_addr, uint32_t size,uint8_t *buff
uint16_t crc = 0; uint16_t crc = 0;
uint32_t addr; uint32_t addr;
for (addr = start_addr; addr < start_addr + size; addr += TRANSFER_BUFFER_SIZE) { for (addr = start_addr; addr < start_addr + size; addr += TRANSFER_BUFFER_SIZE) {
sram_bulk_copy_into_buffer(addr, buffer, TRANSFER_BUFFER_SIZE); sram_bulk_read_buffer(addr, buffer, TRANSFER_BUFFER_SIZE);
crc = do_crc_update(crc, buffer, TRANSFER_BUFFER_SIZE); crc = do_crc_update(crc, buffer, TRANSFER_BUFFER_SIZE);
} }
return crc; return crc;

View File

@@ -20,11 +20,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <avr/pgmspace.h>
#include "debug.h" #include "debug.h"
#include "uart.h" #include "uart.h"
#include "config.h"
extern FILE uart_stdout; extern FILE uart_stdout;
@@ -46,23 +46,4 @@ void debug(int level, char* format, ...) {
} }
#endif #endif
#ifndef NO_INFO
uint8_t buffer_debug[FORMAT_BUFFER_LEN];
#endif
#if defined(NO_DEBUG) && defined(__GNUC__)
#else
void debug_P(int level, PGM_P format, ...) {
#ifdef NO_DEBUG
#else
va_list args;
if (!(debug_level & level))
return;
strlcpy_P(buffer_debug,format,FORMAT_BUFFER_LEN);
va_start(args, format);
vprintf(buffer_debug, args);
va_end(args);
#endif
}
#endif

View File

@@ -26,7 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <avr/pgmspace.h>
#if defined(NO_DEBUG) && defined(__GNUC__) #if defined(NO_DEBUG) && defined(__GNUC__)
/* gcc's cpp has extensions; it allows for macros with a variable number of /* gcc's cpp has extensions; it allows for macros with a variable number of
@@ -39,17 +39,5 @@ void debug(int level, char *format, ...);
#endif #endif
#if defined(NO_DEBUG) && defined(__GNUC__)
/* gcc's cpp has extensions; it allows for macros with a variable number of
arguments. We use this extension here to preprocess pmesg away. */
#define debug_P(level, format, args...) ((void)0)
#else
void debug_P(int level, PGM_P format, ...);
/* print a message, if it is considered significant enough.
Adapted from [K&R2], p. 174 */
#endif
#endif /* DEBUG_H */ #endif /* DEBUG_H */

96
avr/usbload/dir.c Normal file
View File

@@ -0,0 +1,96 @@
/*
* =====================================================================================
*
* ________ .__ __ ________ ____ ________
* \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
* / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
* / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
* \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
* \__> \/ \/ \/ \/ \/
*
* www.optixx.org
*
*
* Version: 1.0
* Created: 07/21/2009 03:32:16 PM
* Author: david@optixx.org
*
* =====================================================================================
*/
#include "dir.h"
#include "file.h"
#include "fat.h"
#include "debug.h"
#include "sram.h"
#include "config.h"
#include <string.h>
uint16_t position = 0;
extern struct File file;
void dir_entry_start(){
position = 0;
}
void dir_entry_dump(uint32_t addr, dir_ent_t* ent){
debug(DEBUG_FAT,"dir_entry_dump: addr=0x%06lx id=%li name=%s size=%li attr=%i\n", addr, ent->id, ent->file_name,
ent->file_size, ent->file_attr);
}
void dir_entry_add(uint32_t id, uint8_t* file_name,uint32_t file_size,uint8_t file_attr){
uint32_t addr;
dir_ent_t ent;
strncpy(ent.file_name,file_name,13);
ent.id = id;
ent.file_size = file_size;
ent.file_attr = file_attr;
addr = DIR_ENTRY_LOC + (position << DIR_ENTRY_SIZE_SHIFT );
sram_bulk_copy(addr, (uint8_t *) &ent, DIR_ENTRY_SIZE );
dir_entry_dump(addr, &ent);
position++;
}
void dir_entry_header(uint16_t idx, uint8_t * header){
uint32_t addr;
addr = DIR_ENTRY_LOC + ( idx << DIR_ENTRY_SIZE_SHIFT ) + DIR_ENTRY_HEADER_OFF;
sram_bulk_copy(addr, (uint8_t *) header, DIR_ENTRY_HEADER_SIZE);
}
uint32_t dir_entry_get(uint32_t idx, dir_ent_t* ent){
uint32_t addr;
addr = DIR_ENTRY_LOC + ( idx << DIR_ENTRY_SIZE_SHIFT );
sram_bulk_read_buffer( addr, (uint8_t *) ent, DIR_ENTRY_SIZE);
return addr;
}
void dir_entry_loop(){
uint8_t i;
uint8_t j;
uint32_t addr;
dir_ent_t ent;
for (i=0; i< position; i++){
addr = dir_entry_get(i,&ent);
dir_entry_dump(addr,&ent);
ffopen( ent.file_name );
if (file.length != 524288){
ffclose();
continue;
}
//ffseek(0x7fc0);
for (j=0; j< 64; j++)
printf ("0x%02x " ,ffread());
printf("\n");
ffclose();
}
}

View File

@@ -19,54 +19,46 @@
*/ */
#ifndef __DIR_H__
#define __DIR_H__
#include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h> /* for sei() */
#include <avr/wdt.h>
#define DIR_ENTRY_LOC 0x010000
#define DIR_ENTRY_SIZE 64
#define DIR_ENTRY_SIZE_SHIFT 6
#define DIR_ENTRY_HEADER_SIZE 44
#define DIR_ENTRY_HEADER_OFF 20
#include "usbdrv.h" typedef struct {
#include "oddebug.h" /* This is also an example for using debug uint32_t id; // 4
* macros */ uint8_t file_name[13]; // 8.3 = 12 + 1 = 13
#include "debug.h" uint32_t file_size; // 4
#include "info.h" uint8_t file_attr; // 1
#include "sram.h" uint8_t snes_header[41]; // 41
} dir_ent_t; // 64
void (*jump_to_app) (void) = 0x0000;
void irq_init(){
cli();
PCMSK3 |=(1<<PCINT27);
PCICR |= (1<<PCIE3);
sei();
}
void irq_stop(){ void dir_entry_start();
cli(); void dir_entry_add(uint32_t id, uint8_t* file_name,uint32_t file_size,uint8_t file_attr);
PCMSK3 &=~(1<<PCINT27); void dir_entry_header(uint16_t position, uint8_t * header);
sei();
}
void leave_application(void) /*
{
cli();
usbDeviceDisconnect();
wdt_enable(WDTO_15MS);
while (1);
} lo:
0x7fc0
0x7fc0 + 0x200
hi:
ISR (SIG_PIN_CHANGE3) 0xffc0
{ 0xffc0 + 0x200
if (snes_reset_test()){
info_P(PSTR("Catch SNES reset button\n")); emulated reset vector MSB must be set
info_P(PSTR("Set watchdog...\n"));
leave_application(); sei
} clc
} xce
*/
#endif

View File

@@ -47,21 +47,21 @@ void dump_packet(uint32_t addr, uint32_t len, uint8_t * packet)
continue; continue;
} }
if (clear) { if (clear) {
info_P(PSTR("*\n")); info("*\n");
clear = 0; clear = 0;
} }
info_P(PSTR("%08lx:"), addr + i); info("%08lx:", addr + i);
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++) {
info_P(PSTR(" %02x"), packet[i + j]); info(" %02x", packet[i + j]);
} }
info_P(PSTR(" |")); info(" |");
for (j = 0; j < 16; j++) { for (j = 0; j < 16; j++) {
if (packet[i + j] >= 33 && packet[i + j] <= 126) if (packet[i + j] >= 33 && packet[i + j] <= 126)
info_P(PSTR("%c"), packet[i + j]); info("%c", packet[i + j]);
else else
info_P(PSTR(".")); info(".");
} }
info_P(PSTR("|\n")); info("|\n");
} }
} }
@@ -72,11 +72,11 @@ void dump_memory(uint32_t bottom_addr, uint32_t top_addr)
sram_bulk_read_start(bottom_addr); sram_bulk_read_start(bottom_addr);
for ( addr = bottom_addr; addr < top_addr; addr++) { for ( addr = bottom_addr; addr < top_addr; addr++) {
if (addr%0x10 == 0) if (addr%0x10 == 0)
info_P(PSTR("\n%08lx:"), addr); info("\n%08lx:", addr);
byte = sram_bulk_read(); byte = sram_bulk_read();
sram_bulk_read_next(); sram_bulk_read_next();
info_P(PSTR(" %02x"), byte); info(" %02x", byte);
} }
info_P(PSTR("\n")); info("\n");
sram_bulk_read_end(); sram_bulk_read_end();
} }

668
avr/usbload/fat.c Normal file
View File

@@ -0,0 +1,668 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include "fat.h"
#include "file.h"
#include "mmc.h"
#include "config.h"
struct Fat fat; // wichtige daten/variablen der fat
struct File file; // wichtige dateibezogene daten/variablen
#if (WRITE==1)
// ***************************************************************************************************************
// schreibt sektor nummer:sec auf die karte (puffer:sector) !!
// setzt bufferFlag=0 da puffer nicht dirty sein kann nach schreiben !
// ***************************************************************************************************************
uint8_t fat_writeSector(uint32_t sec)
{
fat.bufferDirty = 0; // buffer kann nicht dirty sein weil wird geschrieben
return (mmc_write_sector(sec, fat.sector)); // schreiben von sektor puffer
}
#endif
// ***************************************************************************************************************
// umrechnung cluster auf 1.sektor des clusters (möglicherweise mehrere sektoren/cluster) !
// ***************************************************************************************************************
uint32_t fat_clustToSec(uint32_t clust)
{
return (fat.dataDirSec + 2 + ((clust - 2) * fat.secPerClust)); // errechnet den 1. sektor der sektoren des clusters
}
// ***************************************************************************************************************
// umrechnung sektor auf cluster (nicht die position im cluster selber!!)
// ***************************************************************************************************************
uint32_t fat_secToClust(uint32_t sec)
{
return ((sec - fat.dataDirSec - 2 + 2 * fat.secPerClust) / fat.secPerClust); // umkerhrfunktion von fat_clustToSec
}
// ***************************************************************************************************************
// läd sektor:sec auf puffer:sector zum bearbeiten im ram !
// setzt currentSectorNr auf richtigen wert (also den sektor der gepuffert ist). es wird geprüft
// ob der gepufferte sektor geändert wurde, wenn ja muss erst geschrieben werden, um diese daten nicht zu verlieren !
// ***************************************************************************************************************
uint8_t fat_loadSector(uint32_t sec)
{
if (sec != fat.currentSectorNr) { // nachladen nötig
#if (WRITE==1)
if (fat.bufferDirty == 1)
fat_writeSector(fat.currentSectorNr); // puffer diry, also vorher schreiben
#endif
mmc_read_sector(sec, fat.sector); // neuen sektor laden
fat.currentSectorNr = sec; // aktualisiert sektor nummer (nummer des gepufferten sektors)
return (0);
}
else
return (0); // alles ok, daten sind schon da (sec==fat.currentSectorNr)
return (1); // fehler
}
// datei lesen funktionen:
// fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir -> fat_loadFileDataFromDir -> fat_cd
// "daten chain"
// ***************************************************************************************************************
// läd die reihe:row des gepufferten sektors auf das struct:file. dort stehen dann
// alle wichgigen daten wie: 1.cluster,länge bei dateien, name des eintrags, reihen nummer (im sektor), attribut use...
// ***************************************************************************************************************
uint8_t fat_loadRowOfSector(uint16_t row)
{
uint8_t i;
row = row << 5; // multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 usw).
void *vsector; // void, damit man schoen umbiegen kann :)
for (i = 0; i < 11; i++)
file.name[i] = fat.sector[row + i]; // datei name, ersten 10 bytes vom 32 byte eintrag.
file.attrib = fat.sector[row + 11]; // datei attribut, byte 11.
vsector = &fat.sector[row + 26]; // low word von fist.cluster
file.firstCluster = *(uint16_t *) vsector;
vsector = &fat.sector[row + 20]; // high word von first.cluster
file.firstCluster |= (*(uint16_t *) vsector) << 16;
vsector = &fat.sector[row + 28]; // 4 byte von file.length
file.length = *(uint32_t *) vsector;
return (0);
}
// ***************************************************************************************************************
// geht reihen weise durch sektoren des clusters mit dem startsektor:sec, und sucht nach der datei mit dem
// namen:name. es werden die einzelnen sektoren nachgeladen auf puffer:sector vor dem bearbeiten.
// wird die datei in dem cluster gefunden ist return 0 , sonst return1.
// ***************************************************************************************************************
uint8_t fat_loadFileDataFromCluster(uint32_t sec, char name[])
{
uint8_t r;
uint8_t s = 0;
do { // sektoren des clusters prüfen
r = 0; // neuer sektor, dann reihen von 0 an.
mmc_read_sector(sec + s, fat.sector); // läd den sektor sec auf den puffer fat.sector
fat.currentSectorNr = sec + s; // setzen des aktuellen sektors
do { // reihen des sektors prüfen
fat_loadRowOfSector(r); // zeile 0-15 auf struct file laden
if (file.name[0] == 0) { // wenn man auf erste 0 stößt müsste der rest auch leer sein!
file.row = r; // zeile sichern.
return (1);
}
if (0 == strncmp((char *) file.name, name, 10)) { // zeile r ist gesuchte
file.row = r; // zeile sichern.
return (0);
}
r++;
} while (r < 16); // zählt zeilennummer (16(zeilen) * 32(spalten) == 512 bytes des sektors)
s++;
} while (s < fat.secPerClust); // geht durch sektoren des clusters
return (1); // fehler (datei nicht gefunden, oder fehler beim lesen)
}
// ***************************************************************************************************************
// wenn dir == 0 dann wird das root direktory durchsucht, wenn nicht wird der ordner cluster-chain gefolgt, um
// die datei zu finden. es wird das komplette directory in dem man sich befindet durchsucht.
// bei fat16 wird der rootDir berreich durchsucht, bei fat32 die cluster chain des rootDir.
// ***************************************************************************************************************
uint8_t fat_loadFileDataFromDir(char name[])
{
uint16_t s;
if (fat.dir == 0 && fat.fatType == 16) { // IM ROOTDIR. fat16
for (s = 0; s < (uint16_t) (fat.dataDirSec + 2 - fat.rootDir); s++) { // zählt durch RootDir sektoren (errechnet anzahl
// rootDir sektoren).
if (0 == fat_loadFileDataFromCluster(fat.rootDir + s, name))
return (0); // sucht die datei, wenn da, läd daten (1.cluster usw)
}
}
else {
uint32_t i;
if (fat.dir == 0 && fat.fatType == 32)
i = fat.rootDir; // IM ROOTDIR. fat32
else
i = fat.dir; // NICHT ROOTDIR
while (!((i == 0xfffffff && fat.fatType == 32) || (i == 0xffff && fat.fatType == 16))) { // prüft ob weitere sektoren zum
// lesen da sind (fat32||fat16)
if (0 == fat_loadFileDataFromCluster(fat_clustToSec(i), name))
return (0); // lät die daten der datei auf struct:file. datei gefunden (umrechnung auf absoluten sektor)
i = fat_getNextCluster(i); // liest nächsten cluster des dir-eintrags (unterverzeichniss größer 16 einträge)
}
}
return (1); // datei/verzeichniss nicht gefunden
}
#if (SMALL_FILE_SYSTEM==0)
// ***************************************************************************************************************
// start immer im root Dir. start in root dir (dir==0).
// es MUSS in das direktory gewechselt werden, in dem die datei zum lesen/anhängen ist (außer root, da startet mann)!
// ***************************************************************************************************************
uint8_t fat_cd(char name[])
{
if (name[0] == 0) { // ZUM ROOTDIR FAT16/32
fat.dir = 0; // root dir
return (0);
}
if (0 == fat_loadFileDataFromDir(name)) { // NICHT ROOTDIR (fat16/32)
fat.dir = file.firstCluster; // zeigt auf 1.cluster des dir (fat16/32)
return (0);
}
return (1); // dir nicht gewechselt (nicht da?) !!
}
#endif
#if (WRITE==1)
// datei anlegen funktionen :
// ***************************************************************************************************************
// sucht leeren eintrag (zeile) im cluster mit dem startsektor:secStart.
// wird dort kein freier eintrag gefunden ist return (1).
// wird ein freier eintrag gefunden, ist die position der freien reihe auf file.row abzulesen und return (0).
// der sektor mit der freien reihe ist auf dem puffer:sector gepuffert.
// ****************************************************************************************************************
uint8_t fat_getFreeRowOfCluster(unsigned long secStart)
{
uint16_t b; // zum durchgenen der sektor bytes
uint8_t s = 0; // sektoren des clusters.
do {
file.row = 0; // neuer sektor(oder 1.sektor), reihen von vorne.
if (0 == fat_loadSector(secStart + s)) { // laed sektor auf puffer fat.sector
for (b = 0; b < 512; b = b + 32) { // zaehlt durch zeilen (0-15).
if (fat.sector[b] == 0x00 || fat.sector[b] == 0xE5)
return (0); // prueft auf freihen eintrag (leer oder geloescht == OK!).
file.row++; // zählt reihe hoch (nächste reihe im sektor).
}
}
s++; // sektoren des clusters ++ weil einen geprüft.
} while (s < fat.secPerClust); // geht die sektoren des clusters durch (moeglicherweise auch nur 1. sektor).
return (1); // nicht gefunden in diesem cluster (== nicht OK!).
}
// ***************************************************************************************************************
// sucht leeren eintrag (zeile) im directory mit dem startcluster:dir.
// geht die cluster chain des direktories durch. dabei werden auch alle sektoren der cluster geprüft.
// wird dort kein freier eintrag gefunden, wird ein neuer leerer cluster gesucht, verkettet und der
// 1. sektor des freien clusters geladen. die reihe wird auf den ersten eintrag gesetzt, da frei.
// anhand der reihe kann man nun den direktory eintrag vornehmen, und auf die karte schreiben.
// ****************************************************************************************************************
void fat_getFreeRowOfDir(uint32_t dir)
{
uint32_t start = dir;
// solange bis ende cluster chain.
while (!
((dir == 0xfffffff && fat.fatType == 32)
|| (dir == 0xffff && fat.fatType == 16))) {
if (0 == fat_getFreeRowOfCluster(fat_clustToSec(dir)))
return; // freien eintrag in clustern, des dir gefunden !!
start = dir;
dir = fat_getNextCluster(dir);
} // wenn aus schleife raus, kein freier eintrag da -> neuer cluster nötig.
dir = fat_secToClust(fat.startSectors); // dir ist jetzt neuer cluster zum verketten !
fat_setCluster(start, dir); // cluster-chain mit neuem cluster verketten
fat_setCluster(dir, 0x0fffffff); // cluster-chain ende markieren
// es muessen neue gesucht werden, weil der bekannte aus file.c ja grade verkettet wurden. datei eintrag passte nicht mehr ins dir...
fat_getFreeClustersInRow(2); // neue freie cluster suchen, für datei.
file.firstCluster = fat_secToClust(fat.startSectors); // 1. cluster der datei
file.lastCluster = fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei
fat.currentSectorNr = fat_clustToSec(dir); // setzen des richtigen sektors, also auf den 1. der neu verketteten
uint16_t j = 511;
do {
fat.sector[j] = 0x00; // schreibt puffer fat.sector voll mit 0x00==leer
} while (j--);
uint8_t i = 1; // ab 1 weil der 1.sektor des clusters eh noch beschrieben wird...
do {
fat_writeSector(fat.currentSectorNr + i); // löschen des cluster (überschreibt mit 0x00), wichtig bei ffls,
i++;
} while (i < fat.secPerClust);
file.row = 0; // erste reihe frei, weil grad neuen cluster verkettet !
}
// ***************************************************************************************************************
// erstellt 32 byte eintrag einer datei, oder verzeichnisses im puffer:sector.
// erstellt eintrag in reihe:row, mit namen:name usw... !!
// muss noch auf die karte geschrieben werden ! nicht optimiert auf geschwindigkeit.
// ***************************************************************************************************************
void fat_makeRowDataEntry(uint16_t row, char name[], uint8_t attrib,
uint32_t cluster, uint32_t length)
{
fat.bufferDirty = 1; // puffer beschrieben, also neue daten darin(vor lesen muss geschrieben werden)
row = row << 5; // multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 ... zeile
// 15=480)
uint8_t i; // byte zähler in reihe von sektor (32byte eintrag)
uint8_t *bytesOfSec = &fat.sector[row]; // zeiger auf sector bytes
void *vsector;
for (i = 0; i < 11; i++)
*bytesOfSec++ = name[i]; // namen schreiben
*bytesOfSec++ = attrib; // attrib schreiben
vsector = &fat.sector[row + 12];
*(uint32_t *) vsector++ = 0x01010101; // unnoetige felder beschreiben
*(uint32_t *) vsector = 0x01010101;
vsector = &fat.sector[row + 20];
*(uint16_t *) vsector = (cluster & 0xffff0000) >> 16; // low word von cluster
vsector = &fat.sector[row + 22];
*(uint32_t *) vsector = 0x01010101; // unnoetige felder beschreiben
vsector = &fat.sector[row + 26];
*(uint16_t *) vsector = (cluster & 0x0000ffff); // high word von cluster
vsector = &fat.sector[row + 28];
*(uint32_t *) vsector = length; // laenge
}
// ***************************************************************************************************************
// macht den datei eintrag im jetzigen verzeichniss (fat.dir).
// file.row enthält die reihen nummer des leeren eintrags, der vorher gesucht wurde, auf puffer:sector ist der gewünschte
// sektor gepuffert. für fat16 im root dir muss andere funktion genutzt werden, als fat_getFreeRowOfDir (durchsucht nur dirs).
// fat.rootDir enthält bei fat32 den start cluster des directory, bei fat16 den 1. sektor des rootDir bereichs!
// ***************************************************************************************************************
void fat_makeFileEntry(char name[], uint8_t attrib,
uint32_t length)
{
uint16_t s; // zähler für root dir sektoren fat16
if (fat.dir == 0 && fat.fatType == 32)
fat_getFreeRowOfDir(fat.rootDir); // IM ROOT DIR (fat32)
else if (fat.dir == 0 && fat.fatType == 16) { // IM ROOT DIR (fat16)
for (s = 0; s < (uint16_t) (fat.dataDirSec + 2 - fat.rootDir); s++) { // zählt durch RootDir sektoren (errechnet anzahl
// rootDir sektoren).
if (0 == fat_getFreeRowOfCluster(fat.rootDir + s))
break; // geht durch sektoren des root dir.
}
}
else
fat_getFreeRowOfDir(fat.dir); // NICHT ROOT DIR fat32/fat16
fat_makeRowDataEntry(file.row, name, attrib, file.firstCluster, length); // schreibt file eintrag auf puffer
fat_writeSector(fat.currentSectorNr); // schreibt puffer auf karte
}
#endif
// fat funktionen:
// ***************************************************************************************************************
// sucht nötige folge Cluster aus der fat !
// erster daten cluster = 2, ende einer cluster chain 0xFFFF (fat16) oder 0xFFFFFFF, 0xFFFFFF8 (fat32),
// stelle des clusters in der fat, hat als wert, den nächsten cluster. (1:1 gemapt)!
// ***************************************************************************************************************
uint32_t fat_getNextCluster(uint32_t oneCluster)
{
// FAT 16**************FAT 16
if (fat.fatType == 16) {
uint32_t i = oneCluster >> 8;; // (i=oneCluster/256)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab)
uint32_t j = (oneCluster << 1) - (i << 9); // (j=(oneCluster-256*i)*2 == 2*oneCluster-512*i)errechnet das low byte von
// oneCluster
if (0 == fat_loadSector(i + fat.fatSec)) { // ob neu laden nötig, wird von fat_loadSector geprüft
void *bytesOfSec = &fat.sector[j]; // zeiger auf puffer
return *(uint16_t *) bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :)
}
}
// FAT 32**************FAT 32
else {
uint32_t i = oneCluster >> 7; // (i=oneCluster/128)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab)
uint32_t j = (oneCluster << 2) - (i << 9); // (j=(oneCluster-128*i)*4 == oneCluster*4-512*i)errechnet das low byte von
// oneCluster
if (0 == fat_loadSector(i + fat.fatSec)) { // ob neu laden nötig wird von fat_loadSector geprüft
void *bytesOfSec = &fat.sector[j]; // zeiger auf puffer
return *(uint32_t *) bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :)
}
}
return (0);
}
// ***************************************************************************************************************
// sucht verkettete cluster einer datei, die in einer reihe liegen. worst case: nur ein cluster.
// sieht in der fat ab dem cluster offsetCluster nach. sucht die anzahl von MAX_CLUSTERS_IN_ROW,
// am stück,falls möglich. prüft ob der cluster neben offsetCluster dazu gehört...
// setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren
// ***************************************************************************************************************
void fat_getFatChainClustersInRow(uint32_t offsetCluster)
{
uint16_t i = 0;
fat.startSectors = fat_clustToSec(offsetCluster); // setzen des 1. sektors der datei
fat.endSectors = fat.startSectors;
do {
if ((offsetCluster + 1 + i) == fat_getNextCluster(offsetCluster + i))
fat.endSectors += fat.secPerClust; // zählen der zusammenhängenden sektoren
else {
file.lastCluster = offsetCluster + i; // cluster daneben gehört nicht dazu, somit ist offset+i der letzte bekannte
break;
}
} while (i++ < MAX_CLUSTERS_IN_ROW);
fat.endSectors += fat.secPerClust - 1;
}
#if (WRITE==1)
// ***************************************************************************************************************
// sucht freie zusammenhängende cluster aus der fat. maximal MAX_CLUSTERS_IN_ROW am stück.
// erst wir der erste frei cluster gesucht, ab offsetCluster(iklusive) und dann wird geschaut, ob der
// daneben auch frei ist. setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren
// ***************************************************************************************************************
void fat_getFreeClustersInRow(uint32_t offsetCluster)
{
uint16_t i = 1; // variable für anzahl der zu suchenden sektoren
while (fat_getNextCluster(offsetCluster))
offsetCluster++; // suche des 1. freien clusters
fat.startSectors = fat_clustToSec(offsetCluster); // setzen des startsektors der freien sektoren (umrechnen von cluster zu sektoren)
fat.endSectors = fat.startSectors;
do { // suche der nächsten freien
if (0 == fat_getNextCluster(offsetCluster + i))
fat.endSectors += fat.secPerClust; // zählen der zusammenhängenden sektoren
else
break; // cluster daneben ist nicht frei
} while (i++ < MAX_CLUSTERS_IN_ROW);
fat.endSectors += fat.secPerClust - 1; // -1 weil der erste sektor schon mit zählt z.b. [95,98] = 4 sektoren
}
// ***************************************************************************************************************
// verkettet ab startCluster bis einschließlich endCluster. verkettet auch den letzten bekannten mit den neu übergebenen !
// es ist wegen der fragmentierung der fat nötig, sich den letzten bekannten cluster zu merken,
// damit man bei weiteren cluster in einer reihe die alten cluster noch dazu verketten kann (so sind lücken im verketten möglich).
// ***************************************************************************************************************
void fat_setClusterChain(uint32_t startCluster,
uint16_t endCluster)
{
fat_setCluster(file.lastCluster, startCluster); // ende der chain setzen, bzw verketten der ketten
while (startCluster != endCluster) {
startCluster++;
fat_setCluster(startCluster - 1, startCluster); // verketten der cluster der neuen kette
}
fat_setCluster(startCluster, 0xfffffff); // ende der chain setzen
file.lastCluster = endCluster; // ende cluster der kette updaten
fat_writeSector(fat.currentSectorNr); // schreiben des fat sektors auf die karte
}
// ***************************************************************************************************************
// setzt den cluster inhalt. errechnet den sektor der fat in dem cluster ist, errechnet das low byte von
// cluster und setzt dann byteweise den inhalt:content.
// prüft ob buffer dirty (zu setztender cluster nicht in jetzt gepuffertem).
// prüfung erfolgt in fat_loadSector, dann wird alter vorher geschrieben, sonst gehen dort daten verloren !!
// ***************************************************************************************************************
void fat_setCluster(uint32_t cluster, uint32_t content)
{
// FAT 16**************FAT 16
if (fat.fatType == 16) {
uint32_t i = cluster >> 8; // (i=cluster/256)errechnet den sektor der fat in dem cluster ist (rundet immer ab)
uint32_t j = (cluster << 1) - (i << 9); // (j=(cluster-256*i)*2 == 2*cluster-512*i)errechnet das low byte von
// cluster
if (0 == fat_loadSector(i + fat.fatSec)) { // neu laden (fat_loadSector prüft ob schon gepuffert)
void *bytesOfSec = &fat.sector[j]; // init des zeigers auf unterste adresse
*(uint16_t *) bytesOfSec = content; // weil ram auch little endian geht das so :)
fat.bufferDirty = 1; // zeigt an, dass im aktuellen sector geschrieben wurde
}
}
// FAT 32**************FAT 32
else {
uint32_t i = cluster >> 7; // (i=cluster/128)errechnet den sektor der fat in dem cluster ist (rundet immer ab)
uint32_t j = (cluster << 2) - (i << 9); // (j=(cluster-128*i)*4 == cluster*4-512*i)errechnet das low byte von
// cluster
if (0 == fat_loadSector(i + fat.fatSec)) { // neu laden (fat_loadSector prüft ob schon gepuffert)
void *bytesOfSec = &fat.sector[j]; // init des zeigers auf unterste adresse
*(uint32_t *) bytesOfSec = content; // weil ram auch little endian geht das so :)
fat.bufferDirty = 1; // zeigt an, dass im aktuellen sector geschrieben wurde
}
}
}
// ***************************************************************************************************************
// löscht cluster chain, beginnend ab dem startCluster.
// sucht cluster, setzt inhalt usw.. abschließend noch den cluster-chain ende markierten cluster löschen.
// ***************************************************************************************************************
void fat_delClusterChain(uint32_t startCluster)
{
uint32_t nextCluster = startCluster; // tmp variable, wegen verketteter cluster..
do {
startCluster = nextCluster;
nextCluster = fat_getNextCluster(startCluster);
fat_setCluster(startCluster, 0x00000000);
} while (!
((nextCluster == 0xfffffff && fat.fatType == 32)
|| (nextCluster == 0xffff && fat.fatType == 16)));
fat_writeSector(fat.currentSectorNr);
}
#endif
// ***************************************************************************************************************
// Initialisiert die Fat(16/32) daten, wie: root directory sektor, daten sektor, fat sektor...
// siehe auch Fatgen103.pdf. ist NICHT auf performance optimiert!
// byte/sector, byte/cluster, anzahl der fats, sector/fat ... (halt alle wichtigen daten zum lesen ders datei systems!)
// *****************************************************************<**********************************************
uint8_t fat_loadFatData(uint32_t sec)
{
// offset,size
uint16_t rootEntCnt; // 17,2 größe die eine fat belegt
uint16_t fatSz16; // 22,2 sectors occupied by one fat16
uint32_t fatSz32; // 36,4 sectors occupied by one fat32
void *vsector;
if (0 == mmc_read_sector(sec, fat.sector)) { // lesen von fat sector und bestimmen der wichtigen berreiche
fat.bufferDirty = 0; // init wert des flags
fat.secPerClust = fat.sector[13]; // fat.secPerClust, 13 only (power of 2)
vsector = &fat.sector[14];
fat.fatSec = *(uint16_t *) vsector;
vsector = &fat.sector[17];
rootEntCnt = *(uint16_t *) vsector;
vsector = &fat.sector[22];
fatSz16 = *(uint16_t *) vsector;
fat.rootDir = (((rootEntCnt << 5) + 512) / 512) - 1; // ist 0 bei fat 32, sonst der root dir sektor
if (fat.rootDir == 0) { // FAT32 spezifisch (die prüfung so, ist nicht spezifikation konform !).
vsector = &fat.sector[36];
fatSz32 = *(uint32_t *) vsector;
vsector = &fat.sector[44];
fat.rootDir = *(uint32_t *) vsector;
fat.dataDirSec = fat.fatSec + (fatSz32 * fat.sector[16]); // data sector (beginnt mit cluster 2)
fat.fatType = 32; // fat typ
}
else { // FAT16 spezifisch
fat.dataDirSec = fat.fatSec + (fatSz16 * fat.sector[16]) + fat.rootDir; // data sektor (beginnt mit cluster 2)
fat.rootDir = fat.dataDirSec - fat.rootDir; // root dir sektor, da nicht im datenbereich (cluster)
fat.rootDir += sec; // addiert den startsektor auf "
fat.fatType = 16; // fat typ
}
fat.fatSec += sec; // addiert den startsektor auf
fat.dataDirSec += sec; // addiert den startsektor auf (umrechnung von absolut auf real)
fat.dataDirSec -= 2; // zeigt auf 1. cluster
fat.dir = 0; // dir auf '0'==root dir, sonst 1.Cluster des dir
return (0);
}
return (1); // sector nicht gelesen, fat nicht initialisiert!!
}
// ************************************************************************************************<<***************
// int fat sucht den 1. cluster des dateisystems (fat16/32) auch VBR genannt,
// ************************************************************************************************<<***************
uint8_t fat_initfat(void)
{
uint32_t secOfFirstPartition = 0; // ist 1. sektor der 1. partition aus dem MBR
if (0 == mmc_read_sector(0, fat.sector)) {
void *vsector = &fat.sector[454]; // startsektor bestimmen
secOfFirstPartition = *(uint32_t *) vsector;
// prüfung ob man schon im VBR gelesen hat (0x6964654d = "Medi")
if (secOfFirstPartition == 0x6964654d)
return fat_loadFatData(0); // ist superfloppy
else {
return fat_loadFatData(secOfFirstPartition);
} // ist partitioniert...
}
return (1);
}
#if (SMALL_FILE_SYSTEM==0)
// *****************************************************************************************************************
// bereitet str so auf, dass man es auf die mmc/sd karte schreiben kann.
// wandelt z.b. "t.txt" -> "T TXT" oder "main.c" in "MAIN C " => also immer 8.3 und upper case letter
// VORSICHT es werden keine Prüfungen gemacht !
// *****************************************************************************************************************
char *fat_str(char *str)
{
uint8_t i;
uint8_t j = 0;
uint8_t c;
char tmp[12]; // tmp string zum einfacheren umwandeln
strcpy(tmp, str);
for (i = 0; i < 11; i++)
str[i] = ' '; // als vorbereitung alles mit leerzeichen füllen
str[11] = '\0';
i = 0;
do {
c = toupper(tmp[j]);
if (c == '\0')
return str;
if (c != '.')
str[i] = c;
else
i = 7;
i++;
j++;
} while (i < 12);
return str;
}
#endif

78
avr/usbload/fat.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef _FAT_H
#define _FAT_H
// **************************************************************************************************************************
// WICHTIGE SCHLATER: -> hier kann die code größe angepasst werden, zu lasten der funktionalität !
// die fat nicht fragmentiert ist !
#define SMALL_FILE_SYSTEM 0 // wenn 1 dann ist kleines file system, wenn 0 dann komplette file unterstützung !
#define WRITE 0 // wenn 1 dann ist write an, wenn 0 dann read only !
#define OVER_WRITE 0 // wenn 1 dann kann ffwrite dateien überschreiben (nicht performant), wenn 0 dann nur normales schreiben !
#define MAX_CLUSTERS_IN_ROW 256 // gibt an wie viele cluster am stück ohne fat lookup geschrieben bzw gelesen werden können, wenn die fat nicht fragmentiert ist !
// 1. fat_getFreeRowOfCluster -> fat_getFreeRowOfDir -> fat_makeRowDataEntry -> fat_makeFileEntry -> fat_writeSector "eintrag gemacht !!"
// 2. fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir (-> fat_cd) "daten chain"
// **************************************************************************************************************************
// funktionen
extern uint32_t fat_clustToSec(uint32_t); // rechnet cluster zu 1. sektor des clusters um
extern uint32_t fat_secToClust(uint32_t sec); // rechnet sektor zu cluster um!
extern uint32_t fat_getNextCluster(uint32_t oneCluster); // fat auf nächsten, verketteten cluster durchsuchen
extern uint8_t fat_initfat(void); // initalisierung (durchsucht MBR oder nicht)
extern uint8_t fat_writeSector(uint32_t sec); // schreibt sektor auf karte
extern void fat_setCluster(uint32_t cluster, uint32_t content); // setzt cluster inhalt in der fat
extern void fat_delClusterChain(uint32_t startCluster); // löscht cluster-chain in der fat
extern void fat_getFreeRowOfDir(uint32_t dir); // durchsucht directory nach feiem eintrag
extern void fat_makeFileEntry(char name[], uint8_t attrib,
uint32_t length);
extern uint8_t fat_loadSector(uint32_t sec); // läd übergebenen absoluten sektor
extern uint8_t fat_loadFileDataFromDir(char name[]); // durchsucht das aktuelle directory
extern uint8_t fat_cd(char *); // wechselt directory (start im rootDir)
extern uint8_t fat_loadFatData(uint32_t); // läd fat daten
extern uint8_t fat_getFreeRowOfCluster(unsigned long secStart); // durchsucht cluster nach freiem eintrag
extern void fat_getFreeClustersInRow(uint32_t offsetCluster); // sucht zusammenhängende freie cluster aus der fat
extern void fat_getFatChainClustersInRow(uint32_t offsetCluster); // sucht fat-chain cluster die zusammenhängen
extern void fat_makeRowDataEntry(uint16_t row, char name[],
uint8_t attrib,
uint32_t cluster,
uint32_t length);
extern uint8_t fat_loadRowOfSector(uint16_t); // läd reihe des geladen sektors auf struct:file
extern uint8_t fat_loadFileDataFromCluster(uint32_t sec, char name[]); // durchsucht die reihen des geladenen sektors
extern void fat_setClusterChain(uint32_t newOffsetCluster,
uint16_t length);
extern char *fat_str(char *str); // wandelt einen string so, dass er der fat konvention entspricht !
// **************************************************************************************************************************
// variablen
extern struct Fat { // fat daten (1.cluster, root-dir, dir usw.)
uint8_t sector[512]; // der puffer für sektoren !
uint8_t bufferDirty; // puffer wurde beschrieben, sector muss geschrieben werden bevor er neu geladen wird
uint32_t currentSectorNr; // aktuell geladener Sektor (in sector) //beschleunigt wenn z.b 2* 512 byte puffer vorhanden, oder
// bei fat operationen im gleichen sektor
uint32_t dir; // Direktory zeiger rootDir=='0' sonst(1.Cluster des dir; start auf root)
uint32_t rootDir; // Sektor(f16)/Cluster(f32) nr root directory
uint32_t dataDirSec; // Sektor nr data area
uint32_t fatSec; // Sektor nr fat area
uint32_t startSectors; // der erste sektor in einer reihe (freie oder verkettete)
uint32_t endSectors;
uint8_t secPerClust; // anzahl der sektoren pro cluster
uint8_t fatType; // fat16 oder fat32 (16 oder 32)
} fat;
extern struct File { // datei infos
uint16_t cntOfBytes; // -nicht direkt aus dem dateisystem- zäht geschriebene bytes eines sektors
uint8_t name[13]; // 0,10 datei Name.ext (8.3 = max 11)(MUSS uint8_t weil E5)
uint8_t attrib; // 11,1 datei Attribut: 8=value name, 32=datei, 16=Verzeichniss, 15=linux kleingeschrieben eintrag
uint8_t row; // reihe im sektor in der die datei infos stehen (reihe 0-15)
uint32_t firstCluster; // 20,2 /26,2 datei 1.cluster hi,low(möglicherweise der einzige) (4-byte)
uint32_t length; // 28,4 datei Länge (4-byte)
uint32_t lastCluster; // -nicht direkt aus dem dateisystem- letzter cluster der ersten kette
uint32_t seek; // schreib position in der datei
} file;
#endif

525
avr/usbload/file.c Normal file
View File

@@ -0,0 +1,525 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "mmc.h"
#include "fat.h"
#include "file.h"
#include "dir.h"
#include "config.h"
// *******************************************************************************************************************************
// 2 möglichkeiten beim öffnen, datei existiert(return 1) oder muss angelegt werden(return 2)
// zuerst wird geprüft ob es die datei im verzeichniss gibt. danach wird entschieden, ob die datei geöffnet wird oder angelegt.
// -beim offnen werden die bekannten cluster gesucht maximal MAX_CLUSTERS_IN_ROW in reihe. dann wird der 1. sektor der datei auf
// den puffer fat.sector geladen. jetzt kann man ffread lesen...
// -beim anlegen werden freie cluster gesucht, maximal MAX_CLUSTERS_IN_ROW in reihe. dann wird das struct file gefüllt.
// danach wird der dateieintrag gemacht(auf karte). dort wird auch geprüft ob genügend platz im aktuellen verzeichniss existiert.
// möglicherweise wird der 1. cluster der datei nochmal geändert. jetzt ist der erste frei sektor bekannt und es kann geschrieben werden.
//*******************************************************************************************************************************
unsigned char ffopen(char name[]){
unsigned char file_flag=fat_loadFileDataFromDir(name); //prüfung ob datei vorhanden und evetuelles laden des file struct
if( file_flag==0 ){ /** Datei existiert, anlegen nicht nötig! **/
fat_getFatChainClustersInRow( file.firstCluster ); // verkettete cluster aus der fat-chain suchen.
fat_loadSector( fat_clustToSec(file.firstCluster) ); // lät die ersten 512 bytes der datei auf puffer:sector.
file.lastCluster=fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei
return 1;
}
#if (WRITE==1) // anlegen ist schreiben !
else{ /** Datei existiert nicht, also anlegen ! (nur wenn schreiben option an ist)**/
fat_getFreeClustersInRow(2); // leere cluster suchen, ab cluster 2.
strcpy((char*)file.name,(char*)name); // --- füllen des file struct, zum abschließenden schreiben.
file.firstCluster=fat_secToClust(fat.startSectors); // 1. cluster der datei
file.lastCluster=file.firstCluster;//fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei
file.attrib=32; // --- file.row wird in der funktion fat_getFreeRowOfDir geschrieben !!
file.length=0; // damit da nix drin steht ^^
fat_makeFileEntry((char *)file.name,file.attrib,0); // DATEI ANLEGEN auf karte
fat.currentSectorNr=fat_clustToSec(file.firstCluster); // setzen des ersten sektors
return 2;
}
#endif
}
//*******************************************************************************************************************************
// schließt die datei operation ab. eigentlich nur nötig wenn geschrieben wurde. es gibt 2 möglichkeiten :
// 1. die datei wird geschlossen und es wurde über die alte datei länge hinaus geschrieben.
// 2. die datei wird geschlossen und man war innerhalb der datei größe, dann muss nur der aktuelle sektor geschrieben werden.
// der erste fall ist komplizierter, weil ermittelt werden muss wie viele sektoren neu beschrieben wurden um diese zu verketten
// und die neue datei länge muss ermitt weden. abschließend wird entweder (fall 2) nur der aktuelle sektor geschrieben, oder
// der aktuallisierte datei eintrag und die cluster (diese werden verkettet, siehe fileUpdate() ).
// *******************************************************************************************************************************
uint8_t ffclose(void)
{
#if (WRITE==1) /** 2 möglichkeiten beim schließen !! (lesend spielt keine rolle, nichts muss geupdatet werden) **/
if (file.length < (file.seek + file.cntOfBytes))
fileUpdate(); /** 1.) es wurde über die alte datei größe hinaus geschrieben **/
else if (fat.bufferDirty == 1)
fat_writeSector(fat.currentSectorNr); /** 2.) nicht über alte datei länge hinaus **/
#endif
file.cntOfBytes = 0; // init werte der nötigen zähler
file.seek = 0;
return (0);
}
// *******************************************************************************************************************************
// updatet datei eintrag auf der karte und verkettet die dazugehörigen fat cluster.
// füllt den aktuell beschriebenen sektor mit 0x00, da sonst die datei nicht richtig angezeigt wird.
// darf nur während schreibe operationen aufgerufen werden !
// *******************************************************************************************************************************
#if (WRITE==1)
void fileUpdate(void){
unsigned int comp_cntOfBytes=file.cntOfBytes; // sicher nötig wegen schleife...
while( comp_cntOfBytes < 512 ){ // sektor ist beschrieben worden, daher nötigenfalls mit 00 füllen
fat.sector[comp_cntOfBytes]=0x00; // beschreibt ungenutzte bytes mit 0x00
comp_cntOfBytes++;
}
char name[13]; // zum sichern des dateinamens
unsigned long int save_length = file.cntOfBytes + file.seek; // muss gesichert werden, wird sonst von der karte geladen und verändert !
strcpy(name,(char *)file.name); // muss gesichert werden, wird sonst von der karte geladen und verändert !
fat_setClusterChain(fat_secToClust(fat.startSectors),fat_secToClust(fat.currentSectorNr)); // verketten der geschriebenen cluster
fat_loadFileDataFromDir(name); // läd sektor, des datei eintrags, und läd daten von karte auf struct file!
fat_makeRowDataEntry(file.row,name,32,file.firstCluster,save_length); // macht eintrag im puffer
fat_writeSector(fat.currentSectorNr);
}
#endif
// *******************************************************************************************************************************
// offset byte wird übergeben. es wird durch die sektoren der datei gespult (gerechnet), bis der sektor mit dem offset byte erreicht
// ist, dann wird der sektor geladen und der zähler für die bytes eines sektors gesetzt. wenn das byte nicht in den sektoren ist,
// die "vorgesucht" wurden, müssen noch weitere sektoren der datei gesucht werden (sec > fat.endSectors).
// *******************************************************************************************************************************
void ffseek(unsigned long int offset){
#if (WRITE==1)
#if (OVER_WRITE==1) // man muss den dateieintrag updaten, um die daten zu retten !!
if( file.seek > file.length ) fileUpdate(); // fat verketten und datei update auf der karte !
#endif
#endif
fat_getFatChainClustersInRow(file.firstCluster); // suchen von anfang der cluster chain aus !
unsigned long int sec=fat.startSectors; // sektor variable zum durchgehen durch die sektoren
file.seek=0; // weil auch von anfang an der chain gesucht wird mit 0 initialisiert
while(offset>=512){ /** suchen des sektors in dem offset ist **/
sec++; // da byte nicht in diesem sektor ist, muss hochgezählt werden
offset-=512; // ein sektor weniger in dem das byte sein kann
file.seek+=512; // file.seek update, damit bei ffclose() die richtige file.length herauskommt
if ( sec > fat.endSectors ){ // es müssen mehr sektoren der datei gesucht werden
fat_getFatChainClustersInRow(fat_getNextCluster( file.lastCluster ) ); // nachladen von clustern in der chain
sec=fat.startSectors; // setzen des 1. sektors der neu geladenen, zum weitersuchen !
}
}
file.lastCluster=fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei
fat_loadSector(sec); // sektor mit offset byte laden
file.cntOfBytes = offset; // setzen des lese zählers
}
#if (SMALL_FILE_SYSTEM==0)
// *******************************************************************************************************************************
// wechselt verzeichniss. start immer im root Dir.
// MUSS in das direktory gewechselt werden, in dem die datei zum lesen/schreiben ist !
// *******************************************************************************************************************************
uint8_t ffcd(char name[])
{
return (fat_cd(name));
}
// *******************************************************************************************************************************
// zeigt reihen eines clusters an, wird für ffls benötigt !
// es wird ab dem start sektor start_sec, der dazugehörige cluster angezeigt. geprüft wird ob es ein richtiger
// eintrag in der reihe ist (nicht gelöscht, nicht frei usw). die sektoren des clusters werden nachgeladen.
// die dateien werden mit namen und datei größe angezeigt.
// *******************************************************************************************************************************
void lsRowsOfClust(uint32_t start_sec)
{
uint8_t row; // reihen
uint8_t sec = 0; // sektoren
do {
fat_loadSector(start_sec + sec); // sektoren des clusters laden
for (row = 0; row < 16; row++) { // geht durch reihen des sektors
fat_loadRowOfSector(row); // reihe eines sektors (auf dem puffer) laden
if ((file.name[0] != 0xE5 && file.name[0] != 0x00)) {
if (file.attrib == 0x20)
printf("Name: %s Size:%li\n", file.name, file.length);
if (file.attrib == 0x10)
printf("Dir: %s\n", file.name);
}
}
} while (++sec < fat.secPerClust);
}
void ffls(void)
{
uint32_t clust; // cluster
uint16_t s; // fat16 root dir sektoren
if (fat.dir == 0 && fat.fatType == 16) { // IM ROOTDIR. fat16
for (s = 0; s < (uint16_t) (fat.dataDirSec + 2 - fat.rootDir); s++) { // zählt durch RootDir sektoren (errechnet anzahl
lsRowsOfClust(fat.rootDir + s); // zeigt reihen eines root dir clust an
}
printf("Fat16\n");
} else {
if (fat.dir == 0 && fat.fatType == 32)
clust = fat.rootDir; // IM ROOTDIR. fat32
else
clust = fat.dir; // NICHT ROOT DIR
while (!((clust == 0xfffffff && fat.fatType == 32) || (clust == 0xffff && fat.fatType == 16))) { // prüft ob weitere
lsRowsOfClust(fat_clustToSec(clust)); // zeigt reihen des clusters an
clust = fat_getNextCluster(clust); // liest nächsten cluster des dir-eintrags
}
printf("Fat32\n");
}
}
void lsRowsOfClust_smc(uint32_t start_sec)
{
uint8_t row; // reihen
uint8_t sec = 0; // sektoren
do {
fat_loadSector(start_sec + sec); // sektoren des clusters laden
for (row = 0; row < 16; row++) { // geht durch reihen des sektors
fat_loadRowOfSector(row); // reihe eines sektors (auf dem puffer) laden
if ((file.name[0] != 0xE5 && file.name[0] != 0x00)) {
if (file.attrib == 0x20)
dir_entry_add(file.firstCluster, file.name, file.length ,file.attrib);
}
}
} while (++sec < fat.secPerClust);
}
void ffls_smc(void)
{
uint32_t clust; // cluster
uint16_t s; // fat16 root dir sektoren
if (fat.dir == 0 && fat.fatType == 16) { // IM ROOTDIR. fat16
for (s = 0; s < (uint16_t) (fat.dataDirSec + 2 - fat.rootDir); s++) { // zählt durch RootDir sektoren (errechnet anzahl
lsRowsOfClust_smc(fat.rootDir + s); // zeigt reihen eines root dir clust an
}
printf("Fat16\n");
} else {
if (fat.dir == 0 && fat.fatType == 32)
clust = fat.rootDir; // IM ROOTDIR. fat32
else
clust = fat.dir; // NICHT ROOT DIR
while (!((clust == 0xfffffff && fat.fatType == 32) || (clust == 0xffff && fat.fatType == 16))) { // prüft ob weitere
lsRowsOfClust_smc(fat_clustToSec(clust)); // zeigt reihen des clusters an
clust = fat_getNextCluster(clust); // liest nächsten cluster des dir-eintrags
}
printf("Fat32\n");
}
}
// *******************************************************************************************************************************
// wechselt in das parent verzeichniss (ein verzeichniss zurück !)
// die variable fat.dir enthält den start cluster des direktory in dem man sich grade befindet, anhand diesem,
// kann der "." bzw ".." eintrag im ersten sektor des direktory ausgelesen und das parent direktory bestimmt werden.
// *******************************************************************************************************************************
uint8_t ffcdLower(void)
{
if (fat.dir == 0)
return (1); // im root dir, man kann nicht höher !
fat_loadSector(fat_clustToSec(fat.dir)); // läd 1. sektor des aktuellen direktory.
fat_loadRowOfSector(1); // ".." eintrag (parent dir) ist 0 wenn parent == root
fat.dir = file.firstCluster; // dir setzen
return (0);
}
#ifndef __AVR_ATmega8__
// *******************************************************************************************************************************
// erstellt einen dir eintrag im aktuellen verzeichniss.
// prüft ob es den den dir-namen schon gibt, dann wird nichts angelegt.
// wenn ok, dann wird ein freier cluster gesucht, als ende markiert, der eintrag ins dir geschrieben.
// dann wird der cluster des dirs aufbereitet. der erste sektor des clusters enthält den "." und ".." eintrag.
// der "." hat den 1. cluster des eigenen dirs. der ".." eintrag ist der 1. cluster des parent dirs.
// ein dir wird immer mit 0x00 initialisiert ! also alle einträge der sektoren des clusters ( bis auf . und .. einträge)!
// *******************************************************************************************************************************
#if (WRITE==1)
void ffmkdir(char name[]){
unsigned char i;
unsigned int j;
if(0==fat_loadFileDataFromDir(name))return ; // prüft ob dirname im dir schon vorhanden, wenn ja, abbruch !
// cluster in fat setzen, und ordner eintrg im aktuellen verzeichniss machen.
fat_getFreeClustersInRow(2); // holt neue freie cluster, ab cluster 2 ...
fat_setCluster(fat_secToClust(fat.startSectors),0x0fffffff); // fat16/32 cluster chain ende setzen. (neuer ordner in fat)
file.firstCluster=fat_secToClust(fat.startSectors); // dammit fat_makeFileEntry den cluster richtig setzen kann
fat_makeFileEntry(name,0x10,0); // macht dir eintrag im aktuellen verzeichniss (legt ordner im partent verzeichniss an)
// aufbereiten des puffers
j=511;
do{
fat.sector[j]=0x00; //schreibt puffer fat.sector voll mit 0x00==leer
}while(j--);
// aufbereiten des clusters
for(i=1;i<fat.secPerClust;i++){ // ein dir cluster muss mit 0x00 initialisiert werden !
fat_writeSector(fat.startSectors+i); // löschen des cluster (überschreibt mit 0x00), wichtig bei ffls!
}
// aufbereiten des neuen dir sektors mit "." und ".." eintraegen !
fat_makeRowDataEntry(0,". ",0x10,file.firstCluster,0); // macht "." eintrag des dirs
fat_makeRowDataEntry(1,".. ",0x10,fat.dir,0); // macht ".." eintrag des dirs
fat_writeSector(fat_clustToSec(file.firstCluster)); // schreibt einträge auf karte !
}
#endif //WRITE
#endif // ffmkdir wegen atmega8
#endif
#if (WRITE==1)
// *******************************************************************************************************************************
// löscht datei/ordner aus aktuellem verzeichniss, wenn es die datei gibt.
// löscht dateien und ordner rekursiv !
// *******************************************************************************************************************************
uint8_t ffrm(char name[])
{
if (0 == fat_loadFileDataFromDir(name)) { // datei oder ordner ist vorhanden, nur dann lösch operation
if (file.attrib != 0x10) { // ist datei.
fat.sector[file.row << 5] = 0xE5; // datei gelöscht markieren (file.row*32, damit man auf reihen anfang kommt)
if ((file.row - 1) >= 0) { // gibt es einen eintrag davor ?
if (fat.sector[(file.row << 5) - 21] == 0x0f)
fat.sector[(file.row << 5) - 32] = 0xE5; // langer datei eintag auch gelöscht.
}
fat.bufferDirty = 1; // eintrag in puffer gemacht.
if (0 == fat_getNextCluster(file.firstCluster))
return (0); // 1.cluster ist leer ?!?
fat_delClusterChain(file.firstCluster); // löscht die zu der datei gehörige cluster-chain aus der fat.
return (0);
}
// TODO noch nicht optimal. zu viele schreib vorgänge beim löschen von datei einträgen. max bis zu 16/sektor !
else { // ist ordner, dann rekursiv löschen !!
#ifndef __AVR_ATmega8__ // mega8 zu klein für die funktionalität....
uint32_t parent;
uint32_t own;
uint32_t clustsOfDir; // um durch die cluster chain eines dirs zu gehen.
uint8_t cntSecOfClust = 0;
uint8_t i = 0;
fat.sector[file.row << 5] = 0xE5; // löscht dir eintrag
if ((file.row - 1) >= 0) { // gibt es einen eintrag davor (langer datei eintrag)?
if (fat.sector[(file.row << 5) - 21] == 0x0f)
fat.sector[(file.row << 5) - 32] = 0xE5; // langer datei eintag auch gelöscht
}
fat.bufferDirty = 1; // puffer eintrag gemacht
parent = fat.dir; // der ordner in dem der zu löschende ordner ist.
own = file.firstCluster; // der 1. cluster des ordners der zu löschen ist.
clustsOfDir = file.firstCluster; // die "cluster" des zu löschenden ordners
do { // geht durch cluster des dirs
fat_loadSector(fat_clustToSec(clustsOfDir)); // sektor des dirs laden
do { // geht durch sektoren des clusters
do { // geht durch reihen des sektors
fat_loadRowOfSector(i);
if (file.attrib != 0x10 && file.attrib != 0x00 && file.name[0] != 0xE5) { // ist kein ordner,noch nicht
// gelöscht, kein freier eintrag
fat.sector[i << 5] = 0xE5; // erster eintrag der reihe als gelöscht markiert
fat.bufferDirty = 1; // puffer eintrag gemacht
if (file.attrib == 0x20) { // ist datei!
fat_delClusterChain(file.firstCluster); // ist datei, dann cluster-chain der datei löschen
fat_loadSector(fat_clustToSec(clustsOfDir) + cntSecOfClust); // sektor neu laden, weil löschen der
// chain, den puffer nutzt.
}
}
if (file.attrib == 0x10 && file.name[0] == '.') { // "." oder ".." eintrag erkannt, löschen !
fat.sector[i << 5] = 0xE5; // eintrag als gelöscht markiert
fat.bufferDirty = 1; // puffer eintrag gemacht
}
if (file.attrib == 0x10 && file.name[0] != '.' && file.name[0] != 0xE5 && file.name[0] != 0) { // ordner erkannt !
fat.sector[i << 5] = 0xE5; // dir eintrag als gelöscht markiert
fat.bufferDirty = 1; // puffer eintrag gemacht
fat_loadSector(fat_clustToSec(file.firstCluster)); // sektor des dirs laden
clustsOfDir = file.firstCluster; // eigenes dir ist file.firstCluster
own = file.firstCluster; // eigener start cluster/dir
fat_loadRowOfSector(1); // ".." laden um parent zu bestimmen
parent = file.firstCluster; // parent sichern.
cntSecOfClust = 0; // init von gelesenen sektoren und reihen !
i = 0;
continue;
}
if (file.name[0] == 0x00) { // ende des dirs erreicht, wenn nicht voll !!
if (parent == fat.dir) { // erfolgreich alles gelöscht
fat_delClusterChain(own); // cluster chain des ordners löschen
return (0);
}
fat_delClusterChain(own); // cluster chain des ordners löschen
clustsOfDir = parent; // parent ist jetzt wieder arbeisverzeichniss.
own = parent; // arbeitsverzeichniss setzten
fat_loadSector(fat_clustToSec(own)); // sektor des dirs laden
fat_loadRowOfSector(1); // ".." laden um parent zu bestimmen
parent = file.firstCluster; // parent sichern.
cntSecOfClust = 0; // init von gelesenen sektoren und reihen !
i = 0;
continue;
}
i++;
} while (i < 16); // geht durch reihen des sektors.
i = 0; // neuer sektor -> reihen von vorne.
cntSecOfClust++;
fat_loadSector(fat_clustToSec(clustsOfDir) + cntSecOfClust); // läd sektoren des clusters nach
} while (cntSecOfClust < fat.secPerClust); // geht durch sektoren des clusters.
cntSecOfClust = 0; // neuer cluster -> sektoren von vorne.
clustsOfDir = fat_getNextCluster(clustsOfDir); // sucht neuen cluster der cluster-chain.
} while (!((clustsOfDir == 0xfffffff && fat.fatType == 32) || (clustsOfDir == 0xffff && fat.fatType == 16))); // geht
// durch
// cluster
// des
// dirs.
fat_delClusterChain(own); // hier landet man, wenn der ordner voll war (auf cluster "ebene")!!
#endif
}
}
return (1); // fehler, nicht gefunden?
}
#endif
// *******************************************************************************************************************************
// liest 512 bytes aus dem puffer fat.sector. dann werden neue 512 bytes der datei geladen, sind nicht genügend verkettete
// sektoren in einer reihe bekannt, wird in der fat nachgeschaut. dann werden weiter bekannte nachgeladen...
// *******************************************************************************************************************************
inline uint8_t ffread(void)
{
if (file.cntOfBytes == 512) { /** EINEN SEKTOR GLESEN (ab hier 2 möglichkeiten !) **/
file.cntOfBytes = 0; // byte zähler zurück setzen
if (fat.currentSectorNr == fat.endSectors) { /** 1.) nötig mehr sektoren der chain zu laden (mit ein bisschen glück nur alle 512*MAX_CLUSTERS_IN_ROW bytes)**/
fat_getFatChainClustersInRow(fat_getNextCluster(fat_secToClust(fat.endSectors))); // nachladen von clustern in der chain
fat.currentSectorNr = fat.startSectors - 1; // setzen des nächsten sektors um weiter lesen zu können..
}
fat_loadSector(fat.currentSectorNr + 1); /** 2.) die bekannten in einer reihe reichen noch.(nur alle 512 bytes)**/
}
return fat.sector[file.cntOfBytes++]; // rückgabe, byte des sektors (NACH rückgabe erhöhen von zähler ! )
}
#if (WRITE==1)
#if (OVER_WRITE==0) // nicht überschreibende write funktion
// *******************************************************************************************************************************
// schreibt 512 byte blöcke auf den puffer fat.sector. dann wird dieser auf die karte geschrieben. wenn genügend feie
// sektoren zum beschreiben bekannt sind(datenmenge zu groß), muss nicht in der fat nachgeschaut werden. sollten nicht genügend
// zusammenhängende sektoren bekannt sein, werden die alten verkettet und neue gesucht. es ist nötig sich den letzten bekannten
// einer kette zu merken -> file.lastCluster, um auch nicht zusammenhängende cluster verketten zu können (fat_setClusterChain macht das)!
// *******************************************************************************************************************************
inline void ffwrite(uint8_t c)
{
fat.sector[file.cntOfBytes++] = c; // schreiben des chars auf den puffer sector und zähler erhöhen (pre-increment)
fat.bufferDirty = 1; // puffer dirty weil geschrieben und noch nicht auf karte.
if (file.cntOfBytes == 512) { /** SEKTOR VOLL ( 2 möglichkeiten ab hier !) **/
file.cntOfBytes = 0; // rücksetzen des sektor byte zählers
mmc_write_sector(fat.currentSectorNr, fat.sector); /** 1.) vollen sektor auf karte schreiben **/
fat.bufferDirty = 0; // puffer jetzt clear, weil grade alles geschrieben.
file.seek += 512; // position in der datei erhöhen, weil grade 512 bytes geschrieben
if (fat.currentSectorNr == fat.endSectors) { /** 2.) es ist nötig, neue freie zu suchen und die alten zu verketten (mit ein bischen glück nur alle 512*MAX_CLUSTERS_IN_ROW bytes) **/
fat_setClusterChain(fat_secToClust(fat.startSectors), fat_secToClust(fat.endSectors)); // verketten der beschriebenen
fat_getFreeClustersInRow(file.lastCluster); // suchen von leeren sektoren.
fat.currentSectorNr = fat.startSectors - 1; // setzen des 1. sektors der neuen reihe zum schreiben.
}
fat.currentSectorNr++; // nächsten sektor zum beschreiben.
}
}
#endif
#if (OVER_WRITE==1) // überschreibende write funktion, nicht performant, weil immer auch noch ein sektor geladen werden muss
// *******************************************************************************************************************************
// schreibt 512 byte blöcke auf den puffer fat.sector. dann wird dieser auf die karte geschrieben. wenn genügend feie
// sektoren zum beschreiben bekannt sind, muss nicht in der fat nachgeschaut werden. sollten nicht genügend zusammenhängende
// sektoren bekannt sein(datenmenge zu groß), werden die alten verkettet und neue gesucht. es ist nötig sich den letzten bekannten einer
// kette zu merken -> file.lastCluster, um auch nicht zusammenhängende cluster verketten zu können (fat_setClusterChain macht das)!
// es ist beim überschreiben nötig, die schon beschriebenen sektoren der datei zu laden, damit man die richtigen daten
// hat. das ist blöd, weil so ein daten overhead von 50% entsteht. da lesen aber schneller als schreiben geht, verliert man nicht 50% an
// geschwindigkeit.
// *******************************************************************************************************************************
inline void ffwrite(uint8_t c)
{
fat.sector[file.cntOfBytes++] = c; // schreiben des chars auf den puffer sector und zähler erhöhen (pre-increment)
fat.bufferDirty = 1; // puffer dirty weil geschrieben und noch nicht auf karte.
if (file.cntOfBytes == 512) { /** SEKTOR VOLL ( 2 möglichkeiten ab hier !) **/
file.cntOfBytes = 0; // rücksetzen des sektor byte zählers.
mmc_write_sector(fat.currentSectorNr, fat.sector); /** 1.) vollen sektor auf karte schreiben**/
fat.bufferDirty = 0; // puffer jetzt clear, weil grade alles geschrieben.
file.seek += 512; // position in der datei erhöhen, weil grade 512 bytes geschrieben.
if (fat.currentSectorNr == fat.endSectors) { /** 2.) es ist nötig, neue freie zu suchen und die alten zu verketten (mit ein bischen glück nur alle 512*MAX_CLUSTERS_IN_ROW bytes) **/
if (file.seek > file.length) { // außerhalb der datei !!
fat_setClusterChain(fat_secToClust(fat.startSectors), fat_secToClust(fat.endSectors)); // verketten der beschriebenen.
fat_getFreeClustersInRow(file.lastCluster); // neue leere sektoren benötigt, also suchen.
} else {
fat_getFatChainClustersInRow(fat_getNextCluster(file.lastCluster)); // noch innerhalb der datei, deshlab verkettete
// suchen.
}
fat.currentSectorNr = fat.startSectors - 1; // setzen des 1. sektors der neuen reihe zum schreiben.
}
fat.currentSectorNr++; // nächsten sektor zum beschreiben.
mmc_read_sector(fat.currentSectorNr, fat.sector); // wegen überschreiben, muss der zu beschreibende sektor geladen werden...
}
}
#endif
// *******************************************************************************************************************************
// schreibt string auf karte, siehe ffwrite()
// *******************************************************************************************************************************
inline void ffwrites(const char *s)
{
while (*s)
ffwrite(*s++);
}
#endif

33
avr/usbload/file.h Normal file
View File

@@ -0,0 +1,33 @@
#ifndef _FILE_H
#define _FILE_H
// **************************************************************************************************************************
// funktionen
extern inline uint8_t ffread(void); // liest byte-weise aus der datei (puffert immer 512 bytes zwischen)
extern inline void ffwrite(uint8_t c); // schreibt ein byte in die geöffnete datei
extern inline void ffwrites(const char *s); // schreibt string auf karte
extern uint8_t ffopen(char name[]); // kann immer nur 1 datei bearbeiten.
extern uint8_t ffclose(void); // muss aufgerufen werden bevor neue datei bearbeitet wird.
extern void ffseek(uint32_t offset); // setzt zeiger:bytesOfSec auf position in der geöffneten datei.
extern uint8_t ffcd(char name[]); // wechselt direktory
extern void ffls(void); // zeigt direktory inhalt an
extern void ffls_smc(void); // zeigt direktory inhalt an
extern uint8_t ffcdLower(void); // geht ein direktory zurück, also cd.. (parent direktory)
extern uint8_t ffrm(char name[]); // löscht datei aus aktuellem verzeichniss.
extern void ffmkdir(char name[]); // legt ordner in aktuellem verzeichniss an.
void lsRowsOfClust(uint32_t start_sec); // zeigt reihen eines clusters an, ab start_sec
void fileUpdate(void); // updatet datei eintrag auf karte
// **************************************************************************************************************************//
// #######################################################################################################################
#endif

0
tools/mmc-0.5.4/hardware.h → avr/usbload/hardware.h Normal file → Executable file
View File

View File

@@ -20,12 +20,9 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <avr/pgmspace.h>
#include "info.h" #include "info.h"
#include "uart.h" #include "uart.h"
#include "config.h"
@@ -49,26 +46,4 @@ void info(char* format, ...) {
} }
#endif #endif
#ifndef NO_INFO
uint8_t buffer_info[FORMAT_BUFFER_LEN];
#endif
#if defined(NO_INFO) && defined(__GNUC__)
#define info(format, args...) ((void)0)
#else
void info_P(PGM_P format, ...) {
#ifdef NO_INFO
#else
strlcpy_P(buffer_info,format,FORMAT_BUFFER_LEN);
va_list args;
va_start(args, format);
vprintf(buffer_info, args);
va_end(args);
#endif
}
#endif

View File

@@ -26,7 +26,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <stdarg.h> #include <stdarg.h>
#include <avr/pgmspace.h>
#if defined(NO_INFO) && defined(__GNUC__) #if defined(NO_INFO) && defined(__GNUC__)
/* gcc's cpp has extensions; it allows for macros with a variable number of /* gcc's cpp has extensions; it allows for macros with a variable number of
@@ -39,15 +39,4 @@ void info(char *format, ...);
#endif #endif
#if defined(NO_INFO) && defined(__GNUC__)
/* gcc's cpp has extensions; it allows for macros with a variable number of
arguments. We use this extension here to preprocess pmesg away. */
#define info_P(format, args...) ((void)0)
#else
void info_P(PGM_P format, ...);
/* print a message, if it is considered significant enough.
Adapted from [K&R2], p. 174 */
#endif
#endif #endif

View File

@@ -1,25 +0,0 @@
/*
* =====================================================================================
*
* ________ .__ __ ________ ____ ________
* \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
* / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
* / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
* \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
* \__> \/ \/ \/ \/ \/
*
* www.optixx.org
*
*
* Version: 1.0
* Created: 07/21/2009 03:32:16 PM
* Author: david@optixx.org
*
* =====================================================================================
*/
#ifndef __IRQ_H__
#define __IRQ_H__
#endif

View File

@@ -1,6 +1,6 @@
/* /*
File: main.smc File: main.smc
Time: Thu, 06 Aug 2009 20:01:38 Time: Sun, 09 Aug 2009 11:41:19
*/ */
#include <avr/pgmspace.h> #include <avr/pgmspace.h>
#include <loader.h> #include <loader.h>

View File

@@ -6,6 +6,4 @@
#define ROM_HUFFMAN_SIZE 0 #define ROM_HUFFMAN_SIZE 0
#define ROM_RLE_SIZE 31091 #define ROM_RLE_SIZE 31091
void irq_init();
#endif #endif

View File

@@ -51,7 +51,7 @@
extern const char _rom[] PROGMEM; extern const char _rom[] PROGMEM;
extern FILE uart_stdout; extern FILE uart_stdout;
uint8_t debug_level = (DEBUG | DEBUG_USB | DEBUG_CRC | DEBUG_SHM); uint8_t debug_level = (DEBUG | DEBUG_USB | DEBUG_CRC | DEBUG_FAT);
uint8_t read_buffer[TRANSFER_BUFFER_SIZE]; uint8_t read_buffer[TRANSFER_BUFFER_SIZE];
uint32_t req_addr = 0; uint32_t req_addr = 0;
@@ -84,7 +84,7 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
req_bank = 0; req_bank = 0;
rx_remaining = 0; rx_remaining = 0;
debug_P(DEBUG_USB, PSTR("USB_BULK_UPLOAD_INIT: %i %i\n"), rq->wValue.word, debug(DEBUG_USB, "USB_BULK_UPLOAD_INIT: %i %i\n", rq->wValue.word,
rq->wIndex.word); rq->wIndex.word);
req_bank_size = (uint32_t) (1L << rq->wValue.word); req_bank_size = (uint32_t) (1L << rq->wValue.word);
req_bank_cnt = rq->wIndex.word; req_bank_cnt = rq->wIndex.word;
@@ -92,8 +92,8 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
req_percent = 0; req_percent = 0;
req_percent_last = 0; req_percent_last = 0;
sync_errors = 0; sync_errors = 0;
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_INIT: bank_size=0x%08lx bank_cnt=0x%x end_addr=0x%08lx\n"), "USB_BULK_UPLOAD_INIT: bank_size=0x%08lx bank_cnt=0x%x end_addr=0x%08lx\n",
req_bank_size, req_bank_cnt, req_addr_end); req_bank_size, req_bank_cnt, req_addr_end);
shared_memory_write(SHARED_MEM_TX_CMD_BANK_COUNT, req_bank_cnt); shared_memory_write(SHARED_MEM_TX_CMD_BANK_COUNT, req_bank_cnt);
@@ -114,12 +114,12 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
if (req_addr && req_addr % req_bank_size == 0) { if (req_addr && req_addr % req_bank_size == 0) {
#ifdef FLT_DEBUG #ifdef FLT_DEBUG
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_ADDR: req_bank=0x%02x addr=0x%08lx time=%.4f\n"), "USB_BULK_UPLOAD_ADDR: req_bank=0x%02x addr=0x%08lx time=%.4f\n",
req_bank, req_addr, timer_stop()); req_bank, req_addr, timer_stop());
#else #else
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_ADDR: req_bank=0x%02x addr=0x%08lx time=%i\n"), "USB_BULK_UPLOAD_ADDR: req_bank=0x%02x addr=0x%08lx time=%i\n",
req_bank, req_addr, timer_stop_int()); req_bank, req_addr, timer_stop_int());
#endif #endif
req_bank++; req_bank++;
@@ -145,8 +145,8 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
req_percent = (uint32_t)( 100 * req_addr ) / req_addr_end; req_percent = (uint32_t)( 100 * req_addr ) / req_addr_end;
if (req_percent!=req_percent_last){ if (req_percent!=req_percent_last){
//debug_P(DEBUG_USB, //debug(DEBUG_USB,
// PSTR("USB_BULK_UPLOAD_ADDR: precent=%i\n", req_percent); // "USB_BULK_UPLOAD_ADDR: precent=%i\n", req_percent);
shared_memory_write(SHARED_MEM_TX_CMD_UPLOAD_PROGESS, req_percent); shared_memory_write(SHARED_MEM_TX_CMD_UPLOAD_PROGESS, req_percent);
sram_bulk_write_start(req_addr); sram_bulk_write_start(req_addr);
} }
@@ -154,8 +154,8 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
#if 0 #if 0
if (req_addr && (req_addr % 0x1000) == 0) { if (req_addr && (req_addr % 0x1000) == 0) {
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_NEXT: bank=0x%02x addr=0x%08lx crc=%04x\n", "USB_BULK_UPLOAD_NEXT: bank=0x%02x addr=0x%08lx crc=%04x\n",
req_bank, req_addr, crc_check_bulk_memory(req_addr - 0x1000, req_bank, req_addr, crc_check_bulk_memory(req_addr - 0x1000,
req_addr, req_addr,
req_bank_size)); req_bank_size));
@@ -163,24 +163,14 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
} }
sram_bulk_write_start(req_addr); sram_bulk_write_start(req_addr);
#endif #endif
#if SHM_SCRATCHPAD
if (!shared_memory_scratchpad_region_save_helper(req_addr)){
debug_P(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_NEXT: scratchpad_region_save_helper was dirty\n"));
sram_bulk_write_start(req_addr);
}
#endif
if (req_addr && (req_addr % req_bank_size) == 0) { if (req_addr && (req_addr % req_bank_size) == 0) {
#ifdef FLT_DEBUG #ifdef FLT_DEBUG
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_NEXT: req_bank=0x%02x addr=0x%08lx time=%.4f\n"), "USB_BULK_UPLOAD_NEXT: req_bank=0x%02x addr=0x%08lx time=%.4f\n",
req_bank, req_addr, timer_stop()); req_bank, req_addr, timer_stop());
#else #else
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_NEXT: req_bank=0x%02x addr=0x%08lx time=%i\n"), "USB_BULK_UPLOAD_NEXT: req_bank=0x%02x addr=0x%08lx time=%i\n",
req_bank, req_addr, timer_stop_int()); req_bank, req_addr, timer_stop_int());
#endif #endif
req_bank++; req_bank++;
@@ -195,11 +185,11 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
*/ */
} else if (rq->bRequest == USB_BULK_UPLOAD_END) { } else if (rq->bRequest == USB_BULK_UPLOAD_END) {
if (req_state != REQ_STATUS_BULK_UPLOAD) { if (req_state != REQ_STATUS_BULK_UPLOAD) {
debug_P(DEBUG_USB, debug(DEBUG_USB,
PSTR("USB_BULK_UPLOAD_END: ERROR state is not REQ_STATUS_BULK_UPLOAD\n")); "USB_BULK_UPLOAD_END: ERROR state is not REQ_STATUS_BULK_UPLOAD\n");
return 0; return 0;
} }
debug_P(DEBUG_USB, PSTR("USB_BULK_UPLOAD_END:\n")); debug(DEBUG_USB, "USB_BULK_UPLOAD_END:\n");
req_state = REQ_STATUS_IDLE; req_state = REQ_STATUS_IDLE;
sram_bulk_write_end(); sram_bulk_write_end();
shared_memory_write(SHARED_MEM_TX_CMD_UPLOAD_END, 0); shared_memory_write(SHARED_MEM_TX_CMD_UPLOAD_END, 0);
@@ -212,7 +202,7 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
req_addr = rq->wValue.word; req_addr = rq->wValue.word;
req_addr = req_addr << 16; req_addr = req_addr << 16;
req_addr = req_addr | rq->wIndex.word; req_addr = req_addr | rq->wIndex.word;
debug_P(DEBUG_USB, PSTR("USB_CRC: addr=0x%08lx \n"), req_addr); debug(DEBUG_USB, "USB_CRC: addr=0x%08lx \n", req_addr);
crc_check_bulk_memory(0x000000, req_addr, req_bank_size); crc_check_bulk_memory(0x000000, req_addr, req_bank_size);
ret_len = 0; ret_len = 0;
/* /*
@@ -220,20 +210,20 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
*/ */
} else if (rq->bRequest == USB_MODE_SNES) { } else if (rq->bRequest == USB_MODE_SNES) {
req_state = REQ_STATUS_SNES; req_state = REQ_STATUS_SNES;
debug_P(DEBUG_USB, PSTR("USB_MODE_SNES:\n")); debug(DEBUG_USB, "USB_MODE_SNES:\n");
ret_len = 0; ret_len = 0;
/* /*
* ------------------------------------------------------------------------- * -------------------------------------------------------------------------
*/ */
} else if (rq->bRequest == USB_MODE_AVR) { } else if (rq->bRequest == USB_MODE_AVR) {
req_state = REQ_STATUS_AVR; req_state = REQ_STATUS_AVR;
debug_P(DEBUG_USB, PSTR("USB_MODE_AVR:\n")); debug(DEBUG_USB, "USB_MODE_AVR:\n");
ret_len = 0; ret_len = 0;
/* /*
* ------------------------------------------------------------------------- * -------------------------------------------------------------------------
*/ */
} else if (rq->bRequest == USB_AVR_RESET) { } else if (rq->bRequest == USB_AVR_RESET) {
debug_P(DEBUG_USB, PSTR("USB_AVR_RESET:\n")); debug(DEBUG_USB, "USB_AVR_RESET:\n");
soft_reset(); soft_reset();
ret_len = 0; ret_len = 0;
/* /*
@@ -245,12 +235,12 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
req_addr = rq->wValue.word; req_addr = rq->wValue.word;
req_addr = req_addr << 16; req_addr = req_addr << 16;
req_addr = req_addr | rq->wIndex.word; req_addr = req_addr | rq->wIndex.word;
debug_P(DEBUG_USB, PSTR("USB_CRC_ADDR: addr=0x%lx size=%i\n"), req_addr, debug(DEBUG_USB, "USB_CRC_ADDR: addr=0x%lx size=%i\n", req_addr,
rq->wLength.word); rq->wLength.word);
req_size = rq->wLength.word; req_size = rq->wLength.word;
req_size = req_size << 2; req_size = req_size << 2;
tx_remaining = 2; tx_remaining = 2;
debug_P(DEBUG_USB, PSTR("USB_CRC_ADDR: addr=0x%lx size=%li\n"), req_addr, debug(DEBUG_USB, "USB_CRC_ADDR: addr=0x%lx size=%li\n", req_addr,
req_size); req_size);
crc = crc_check_memory_range(req_addr, req_size, read_buffer); crc = crc_check_memory_range(req_addr, req_size, read_buffer);
@@ -273,114 +263,111 @@ usbMsgLen_t usbFunctionSetup(uchar data[8])
void usb_connect() void usb_connect()
{ {
uint8_t i = 0; uint8_t i = 0;
info_P(PSTR("USB init\n")); info("USB init\n");
usbDeviceDisconnect(); /* enforce re-enumeration, do this while */ usbDeviceDisconnect(); /* enforce re-enumeration, do this while */
cli(); cli();
info_P(PSTR("USB disconnect\n")); info("USB disconnect\n");
i = 10; i = 10;
while (--i) { /* fake USB disconnect for > 250 ms */ while (--i) { /* fake USB disconnect for > 250 ms */
led_on(); led_on();
_delay_ms(15);
led_off();
_delay_ms(35); _delay_ms(35);
led_off();
_delay_ms(65);
} }
led_on(); led_on();
usbDeviceConnect(); usbDeviceConnect();
info_P(PSTR("USB connect\n")); info("USB connect\n");
} }
void boot_startup_rom() void boot_startup_rom()
{ {
info_P(PSTR("Boot startup rom\n"));
info_P(PSTR("Activate AVR bus\n")); info("Activate AVR bus\n");
avr_bus_active(); avr_bus_active();
info_P(PSTR("IRQ off\n")); info("IRQ off\n");
snes_irq_lo(); snes_irq_lo();
snes_irq_off(); snes_irq_off();
snes_lorom(); snes_lorom();
info("Set Snes lowrom \n");
rle_decode(&_rom, ROM_BUFFER_SIZE, 0x000000); rle_decode(&_rom, ROM_BUFFER_SIZE, 0x000000);
info_P(PSTR("\n"));
#if 1
dump_memory(0x10000 - 0x100, 0x10000); dump_memory(0x10000 - 0x100, 0x10000);
#endif snes_reset_hi();
snes_reset_off();
snes_irq_lo();
snes_irq_off();
info("IRQ off\n");
snes_hirom(); snes_hirom();
snes_wr_disable(); snes_wr_disable();
info("Disable snes WR\n");
snes_bus_active(); snes_bus_active();
info_P(PSTR("Activate SNES bus\n")); info("Activate Snes bus\n");
_delay_ms(20);
send_reset(); send_reset();
_delay_ms(50); _delay_ms(200);
send_reset();
_delay_ms(50);
} }
void banner(){
uint8_t i;
for (i=0;i<40;i++)
info_P(PSTR("\n"));
info_P(PSTR(" ________ .__ __ ________ ____ ________\n"));
info_P(PSTR(" \\_____ \\ __ __|__| ____ | | __\\______ \\ _______ _/_ |/ _____/\n"));
info_P(PSTR(" / / \\ \\| | \\ |/ ___\\| |/ / | | \\_/ __ \\ \\/ /| / __ \\ \n"));
info_P(PSTR(" / \\_/. \\ | / \\ \\___| < | ` \\ ___/\\ / | \\ |__\\ \\ \n"));
info_P(PSTR(" \\_____\\ \\_/____/|__|\\___ >__|_ \\/_______ /\\___ >\\_/ |___|\\_____ / \n"));
info_P(PSTR(" \\__> \\/ \\/ \\/ \\/ \\/ \n"));
info_P(PSTR("\n"));
info_P(PSTR(" www.optixx.org\n"));
info_P(PSTR("\n"));
info_P(PSTR("System Hw: %s Sw: %s\n"),HW_VERSION,SW_VERSION);
}
void globals_init(){
req_addr = 0;
req_addr_end = 0;
req_state = REQ_STATUS_IDLE;
rx_remaining = 0;
tx_remaining = 0;
sync_errors = 0;
}
int main(void) int main(void)
{ {
uart_init(); uart_init();
stdout = &uart_stdout; stdout = &uart_stdout;
banner();
info("Sytem start\n");
system_init(); system_init();
snes_reset_hi();
snes_reset_off();
irq_init(); #if 1
avr_bus_active();
info("Activate AVR bus\n");
info("IRQ off\n");
snes_irq_lo();
snes_irq_off();
info("Set Snes lowrom\n");
snes_lorom();
info("Disable snes WR\n");
snes_wr_disable();
test_sdcard();
#endif
info("Boot startup rom\n");
boot_startup_rom(); boot_startup_rom();
globals_init();
usbInit(); usbInit();
usb_connect(); usb_connect();
while (1) { while (1) {
avr_bus_active(); avr_bus_active();
info_P(PSTR("Activate AVR bus\n")); info("Activate AVR bus\n");
info("IRQ off\n");
snes_irq_lo();
snes_irq_off();
info("Set Snes lowrom\n");
snes_lorom(); snes_lorom();
info_P(PSTR("Disable SNES WR\n")); info("Disable snes WR\n");
snes_wr_disable(); snes_wr_disable();
sei(); sei();
info_P(PSTR("USB poll\n")); info("USB poll\n");
while (req_state != REQ_STATUS_SNES) { while (req_state != REQ_STATUS_SNES) {
usbPoll(); usbPoll();
} }
shared_memory_write(SHARED_MEM_TX_CMD_TERMINATE, 0); shared_memory_write(SHARED_MEM_TX_CMD_TERMINATE, 0);
info("USB poll done\n");
#if SHM_SCRATCHPAD
shared_memory_scratchpad_region_tx_restore();
shared_memory_scratchpad_region_rx_restore();
#endif
info_P(PSTR("USB poll done\n"));
set_rom_mode(); set_rom_mode();
snes_wr_disable(); snes_wr_disable();
info_P(PSTR("Disable SNES WR\n")); info("Disable snes WR\n");
snes_bus_active(); snes_bus_active();
info_P(PSTR("Activate SNES bus\n")); info("Activate Snes bus\n");
irq_stop(); _delay_ms(100);
send_reset(); send_reset();
info_P(PSTR("Poll USB\n"));
while ((req_state != REQ_STATUS_AVR)) { info("Poll\n");
while (req_state != REQ_STATUS_AVR) {
usbPoll(); usbPoll();
#ifdef DO_IRQ #ifdef DO_IRQ
@@ -390,7 +377,7 @@ int main(void)
while (--i) { while (--i) {
_delay_ms(100); _delay_ms(100);
} }
info_P(PSTR("Send IRQ %i\n"), ++irq_count); info("Send IRQ %i\n", ++irq_count);
send_irq(); send_irq();
#endif #endif
@@ -401,24 +388,26 @@ int main(void)
i = 5; i = 5;
while (--i) { while (--i) {
_delay_ms(500); _delay_ms(500);
info_P(PSTR("Wait to switch to snes mode %i\n"), i); info("Wait to switch to snes mode %i\n", i);
} }
if (req_bank_size == 0x8000) { if (req_bank_size == 0x8000) {
snes_lorom(); snes_lorom();
info("Set Snes lowrom \n");
} else { } else {
snes_hirom(); snes_hirom();
info("Set Snes hirom \n");
} }
snes_wr_disable(); snes_wr_disable();
info_P(PSTR("Disable SNES WR\n")); info("Disable snes WR\n");
snes_bus_active(); snes_bus_active();
info_P(PSTR("Activate SNES bus\n")); info("Activate Snes bus\n");
info_P(PSTR("Read 0x3000=%c\n"), c); info("Read 0x3000=%c\n", c);
#endif #endif
} }
irq_init(); info("Boot startup rom\n");
boot_startup_rom(); boot_startup_rom();
globals_init();
} }
return 0; return 0;
} }

220
avr/usbload/mmc.c Normal file
View File

@@ -0,0 +1,220 @@
/*
* ####################################################################################### Connect AVR to MMC/SD
*
* Copyright (C) 2004 Ulrich Radig
*
* Bei Fragen und Verbesserungen wendet euch per EMail an
*
* mail@ulrichradig.de
*
* oder im Forum meiner Web Page : www.ulrichradig.de
*
* Dieses Programm ist freie Software. Sie können es unter den Bedingungen der GNU General Public License, wie von der Free Software
* Foundation veröffentlicht, weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder (nach Ihrer Option) jeder
* späteren Version.
*
* Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE,
* sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU
* General Public License.
*
* Sie sollten eine Kopie der GNU General Public License zusammen mit diesem Programm erhalten haben. Falls nicht, schreiben Sie an die
* Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
* #######################################################################################
*/
#include <avr/io.h>
#include <util/delay.h>
#include "mmc.h"
uint8_t mmc_init()
{
uint16_t Timeout = 0, i;
MMC_REG |= ((1 << MMC_DO) | (1 << MMC_CS) | (1 << MMC_CLK));
MMC_REG &= ~(1 << MMC_DI);
MMC_WRITE |= ((1 << MMC_DO) | (1 << MMC_DI) | (1 << MMC_CS));
_delay_ms(20);
for (i = 0; i < 250; i++) {
MMC_WRITE ^= (1 << MMC_CLK);
_delay_us(4);
}
MMC_WRITE &= ~(1 << MMC_CLK);
_delay_us(10);
MMC_WRITE &= ~(1 << MMC_CS);
_delay_us(3);
uint8_t CMD[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x95 };
while (mmc_write_command(CMD) != 1) {
if (Timeout++ > 20) {
mmc_disable();
return (1);
}
}
Timeout = 0;
CMD[0] = 0x41;
CMD[5] = 0xFF;
while (mmc_write_command(CMD) != 0) {
if (Timeout++ > 800) {
mmc_disable();
return (9);
}
}
return (0);
}
uint8_t mmc_write_command(uint8_t * cmd)
{
uint8_t tmp = 0xff;
uint16_t Timeout = 0;
uint8_t a;
for (a = 0; a < 0x06; a++) {
mmc_write_byte(*cmd++);
}
while (tmp == 0xff) {
tmp = mmc_read_byte();
if (Timeout++ > 50) {
break;
}
}
return (tmp);
}
uint8_t mmc_read_byte(void)
{
uint8_t Byte = 0, j;
for (j = 0; j < 8; j++) {
Byte = (Byte << 1);
MMC_WRITE |= (1 << MMC_CLK);
_delay_us(4);
if (PINB & (1 << MMC_DI)) {
Byte |= 1;
}
else {
Byte &= ~1;
}
MMC_WRITE &= ~(1 << MMC_CLK);
_delay_us(4);
}
return (Byte);
}
void mmc_write_byte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++) {
if (Byte & 0x80) {
MMC_WRITE |= (1 << MMC_DO);
}
else {
MMC_WRITE &= ~(1 << MMC_DO);
}
Byte = (Byte << 1);
MMC_WRITE |= (1 << MMC_CLK);
_delay_us(4);
MMC_WRITE &= ~(1 << MMC_CLK);
_delay_us(4);
}
MMC_WRITE |= (1 << MMC_DO);
}
uint8_t mmc_write_sector(uint32_t addr, uint8_t * Buffer)
{
uint8_t tmp;
uint8_t cmd[] = { 0x58, 0x00, 0x00, 0x00, 0x00, 0xFF };
uint8_t a;
uint16_t i;
addr = addr << 9;
cmd[1] = ((addr & 0xFF000000) >> 24);
cmd[2] = ((addr & 0x00FF0000) >> 16);
cmd[3] = ((addr & 0x0000FF00) >> 8);
tmp = mmc_write_command(cmd);
if (tmp != 0) {
return (tmp);
}
for (a = 0; a < 100; a++) {
mmc_read_byte();
}
mmc_write_byte(0xFE);
for (a = 0; i < 512; i++) {
mmc_write_byte(*Buffer++);
}
mmc_write_byte(0xFF);
mmc_write_byte(0xFF);
if ((mmc_read_byte() & 0x1F) != 0x05)
return (1);
while (mmc_read_byte() != 0xff) {
};
return (0);
}
void mmc_read_block(uint8_t * cmd, uint8_t * Buffer, uint16_t Bytes)
{
uint16_t a;
if (mmc_write_command(cmd) != 0) {
return;
}
while (mmc_read_byte() != 0xfe) {
};
for (a = 0; a < Bytes; a++) {
*Buffer++ = mmc_read_byte();
}
mmc_read_byte();
mmc_read_byte();
return;
}
uint8_t mmc_read_sector(uint32_t addr, uint8_t * Buffer)
{
uint8_t cmd[] = { 0x51, 0x00, 0x00, 0x00, 0x00, 0xFF };
addr = addr << 9;
cmd[1] = ((addr & 0xFF000000) >> 24);
cmd[2] = ((addr & 0x00FF0000) >> 16);
cmd[3] = ((addr & 0x0000FF00) >> 8);
mmc_read_block(cmd, Buffer, 512);
return (0);
}
uint8_t mmc_read_cid(uint8_t * Buffer)
{
uint8_t cmd[] = { 0x4A, 0x00, 0x00, 0x00, 0x00, 0xFF };
mmc_read_block(cmd, Buffer, 16);
return (0);
}
uint8_t mmc_read_csd(uint8_t * Buffer)
{
uint8_t cmd[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0xFF };
mmc_read_block(cmd, Buffer, 16);
return (0);
}

44
avr/usbload/mmc.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* ####################################################################################### Connect ARM to MMC/SD
*
* Copyright (C) 2004 Ulrich Radig #######################################################################################
*/
#ifndef _MMC_H
#define _MMC_H
#define SPI_Mode 0 // 1 = Hardware SPI | 0 = Software SPI
#define MMC_WRITE PORTB
#define MMC_READ PINB
#define MMC_REG DDRB
#define MMC_CS PB4
#define MMC_DO PB6
#define MMC_DI PB5
#define MMC_CLK PB7
#define MMC_WRITE PORTB // Port an der die MMC/SD-Karte angeschlossen ist also des SPI
#define MMC_READ PINB
#define MMC_REG DDRB
extern uint8_t mmc_read_byte(void);
extern void mmc_write_byte(uint8_t);
extern void mmc_read_block(uint8_t *, uint8_t *, unsigned in);
extern uint8_t mmc_init(void);
extern uint8_t mmc_read_sector(unsigned long, uint8_t *);
extern uint8_t mmc_write_sector(unsigned long, uint8_t *);
extern uint8_t mmc_write_command(uint8_t *);
#define mmc_disable() MMC_WRITE|= (1<<MMC_CS);
#define mmc_enable() MMC_WRITE&=~(1<<MMC_CS);
#define nop() __asm__ __volatile__ ("nop" ::)
#endif

View File

@@ -36,7 +36,7 @@ uint8_t rle_decode(PGM_VOID_P in_addr, int32_t in_len, uint32_t out_addr)
{ {
uint8_t in_byte, in_repeat, last_byte; uint8_t in_byte, in_repeat, last_byte;
uint32_t out_len, out_len_left; uint32_t out_len, out_len_left;
info_P(PSTR("RLE decode len=%li addr=0x%08lx\n"), in_len, out_addr); info("RLE decode len=%li addr=0x%08lx\n", in_len, out_addr);
last_byte = 0; last_byte = 0;
out_len_left = out_len; out_len_left = out_len;
@@ -63,7 +63,7 @@ uint8_t rle_decode(PGM_VOID_P in_addr, int32_t in_len, uint32_t out_addr)
if (in_byte == RUNCHAR) { if (in_byte == RUNCHAR) {
INBYTE(in_repeat); INBYTE(in_repeat);
if (in_repeat != 0) { if (in_repeat != 0) {
info_P(PSTR("Orphaned RLE code at start\n")); info("Orphaned RLE code at start\n");
return 1; return 1;
} }
OUTBYTE(RUNCHAR); OUTBYTE(RUNCHAR);
@@ -74,7 +74,7 @@ uint8_t rle_decode(PGM_VOID_P in_addr, int32_t in_len, uint32_t out_addr)
while (in_len > 0) { while (in_len > 0) {
INBYTE(in_byte); INBYTE(in_byte);
if (in_len % 1024 == 0) if (in_len % 1024 == 0)
info_P(PSTR(".")); info(".");
if (in_byte == RUNCHAR) { if (in_byte == RUNCHAR) {
INBYTE(in_repeat); INBYTE(in_repeat);
if (in_repeat == 0) { if (in_repeat == 0) {

View File

@@ -29,7 +29,6 @@
#include "config.h" #include "config.h"
#include "sram.h" #include "sram.h"
#include "debug.h" #include "debug.h"
#include "dump.h"
#include "info.h" #include "info.h"
uint8_t irq_addr_lo; uint8_t irq_addr_lo;
@@ -39,117 +38,6 @@ uint8_t scratchpad_state;
uint8_t scratchpad_cmd; uint8_t scratchpad_cmd;
uint8_t scratchpad_payload; uint8_t scratchpad_payload;
uint8_t scratchpad_region_rx[SHARED_MEM_RX_LOC_SIZE];
uint8_t scratchpad_region_tx[SHARED_MEM_TX_LOC_SIZE];
uint8_t scratchpad_locked_rx = 1;
uint8_t scratchpad_locked_tx = 1;
uint8_t shared_memory_scratchpad_region_save_helper(uint32_t addr){
if(addr > (SHARED_MEM_TX_LOC_STATE + SHARED_MEM_TX_LOC_SIZE) && scratchpad_locked_tx){
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_save_helper: open tx addr=0x%06lx\n"),addr);
shared_memory_scratchpad_region_tx_save();
return 0;
}
if(addr > (SHARED_MEM_RX_LOC_STATE + SHARED_MEM_RX_LOC_SIZE) && scratchpad_locked_rx){
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_save_helper: open rx addr=0x%06lx\n"),addr);
shared_memory_scratchpad_region_rx_save();
return 0;
}
return 1;
}
void shared_memory_scratchpad_region_tx_save()
{
#if 0
uint16_t crc;
crc = crc_check_bulk_memory((uint32_t)SHARED_MEM_TX_LOC_STATE,
(uint32_t)(SHARED_MEM_TX_LOC_STATE + SHARED_MEM_TX_LOC_SIZE), 0x8000);
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_save: crc=%x\n"),crc);
#endif
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_save: unlock\n"));
sram_bulk_copy_into_buffer((uint32_t)SHARED_MEM_TX_LOC_STATE,scratchpad_region_tx,
(uint32_t)SHARED_MEM_TX_LOC_SIZE);
scratchpad_locked_tx = 0;
#if 0
dump_packet(SHARED_MEM_TX_LOC_STATE, SHARED_MEM_TX_LOC_SIZE, scratchpad_region_tx);
dump_memory(SHARED_MEM_TX_LOC_STATE, SHARED_MEM_TX_LOC_STATE + SHARED_MEM_TX_LOC_SIZE);
#endif
}
void shared_memory_scratchpad_region_rx_save()
{
#if 0
uint16_t crc;
crc = crc_check_bulk_memory((uint32_t)SHARED_MEM_RX_LOC_STATE,
(uint32_t)(SHARED_MEM_RX_LOC_STATE + SHARED_MEM_RX_LOC_SIZE), 0x8000);
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_save: crc=%x\n"),crc);
#endif
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_rx_save: unlock\n"));
sram_bulk_copy_into_buffer((uint32_t)SHARED_MEM_RX_LOC_STATE,scratchpad_region_rx,
(uint32_t)SHARED_MEM_RX_LOC_SIZE);
scratchpad_locked_rx = 0;
#if 0
dump_packet(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_RX_LOC_SIZE, scratchpad_region_tx);
dump_memory(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_RX_LOC_STATE + SHARED_MEM_RX_LOC_SIZE);
#endif
}
void shared_memory_scratchpad_region_tx_restore()
{
if (scratchpad_locked_tx)
return;
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_restore: lock\n"));
sram_bulk_copy_from_buffer((uint32_t)SHARED_MEM_TX_LOC_STATE,scratchpad_region_tx,
(uint32_t)SHARED_MEM_TX_LOC_SIZE);
scratchpad_locked_tx = 1;
#if 0
dump_packet(SHARED_MEM_TX_LOC_STATE, SHARED_MEM_TX_LOC_SIZE, scratchpad_region_tx);
dump_memory(SHARED_MEM_TX_LOC_STATE, SHARED_MEM_TX_LOC_STATE + SHARED_MEM_TX_LOC_SIZE);
#endif
#if 0
uint16_t crc;
crc = crc_check_bulk_memory((uint32_t)SHARED_MEM_TX_LOC_STATE,
(uint32_t)(SHARED_MEM_TX_LOC_STATE + SHARED_MEM_TX_LOC_SIZE), 0x8000);
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_restore: crc=%x\n"),crc);
#endif
}
void shared_memory_scratchpad_region_rx_restore()
{
if (scratchpad_locked_rx)
return;
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_tx_save: lock\n"));
sram_bulk_copy_from_buffer((uint32_t)SHARED_MEM_RX_LOC_STATE,scratchpad_region_rx,
(uint32_t)SHARED_MEM_RX_LOC_SIZE);
scratchpad_locked_rx = 1;
#if 0
dump_packet(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_TX_LOC_SIZE, scratchpad_region_rx);
dump_memory(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_TX_LOC_STATE + SHARED_MEM_RX_LOC_SIZE);
#endif
#if 1
uint16_t crc;
crc = crc_check_bulk_memory((uint32_t)SHARED_MEM_RX_LOC_STATE,
(uint32_t)(SHARED_MEM_RX_LOC_STATE + SHARED_MEM_RX_LOC_SIZE), 0x8000);
debug_P(DEBUG_SHM, PSTR("shared_memory_scratchpad_region_rx_restore: crc=%x\n"),crc);
#endif
}
void shared_memory_scratchpad_tx_save() void shared_memory_scratchpad_tx_save()
{ {
scratchpad_state = sram_read(SHARED_MEM_TX_LOC_STATE); scratchpad_state = sram_read(SHARED_MEM_TX_LOC_STATE);
@@ -182,10 +70,7 @@ void shared_memory_irq_restore()
void shared_memory_write(uint8_t cmd, uint8_t value) void shared_memory_write(uint8_t cmd, uint8_t value)
{ {
if (scratchpad_locked_tx) debug(DEBUG_SHM,"shared_memory_write: 0x%04x=0x%02x 0x%04x=0x%02x \n",
debug_P(DEBUG_SHM, PSTR("shared_memory_write: locked_tx\n"));
debug_P(DEBUG_SHM, PSTR("shared_memory_write: 0x%04x=0x%02x 0x%04x=0x%02x \n"),
SHARED_MEM_TX_LOC_CMD, cmd, SHARED_MEM_TX_LOC_PAYLOAD, value); SHARED_MEM_TX_LOC_CMD, cmd, SHARED_MEM_TX_LOC_PAYLOAD, value);
sram_bulk_addr_save(); sram_bulk_addr_save();
@@ -218,7 +103,7 @@ void shared_memory_write(uint8_t cmd, uint8_t value)
shared_memory_scratchpad_tx_restore(); shared_memory_scratchpad_tx_restore();
shared_memory_irq_restore(); shared_memory_irq_restore();
//sram_bulk_addr_restore(); sram_bulk_addr_restore();
} }
@@ -239,9 +124,6 @@ void shared_memory_yield()
int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer) int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer)
{ {
uint8_t state; uint8_t state;
if (scratchpad_locked_rx)
debug_P(DEBUG_SHM, PSTR("shared_memory_write: locked_tx\n"));
state = sram_read(SHARED_MEM_RX_LOC_STATE); state = sram_read(SHARED_MEM_RX_LOC_STATE);
@@ -252,10 +134,10 @@ int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer)
*cmd = sram_read(SHARED_MEM_RX_LOC_CMD); *cmd = sram_read(SHARED_MEM_RX_LOC_CMD);
*len = sram_read(SHARED_MEM_RX_LOC_LEN); *len = sram_read(SHARED_MEM_RX_LOC_LEN);
debug_P(DEBUG_SHM, PSTR("shared_memory_read: 0x%04x=0x%02x 0x%04x=0x%02x \n"), debug(DEBUG_SHM,"shared_memory_read: 0x%04x=0x%02x 0x%04x=0x%02x \n",
SHARED_MEM_RX_LOC_CMD, *cmd, SHARED_MEM_RX_LOC_LEN, *len); SHARED_MEM_RX_LOC_CMD, *cmd, SHARED_MEM_RX_LOC_LEN, *len);
sram_bulk_copy_into_buffer(SHARED_MEM_RX_LOC_PAYLOAD,buffer, *len); sram_bulk_read_buffer(SHARED_MEM_RX_LOC_PAYLOAD,buffer, *len);
sram_write(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_RX_AVR_RTS); sram_write(SHARED_MEM_RX_LOC_STATE, SHARED_MEM_RX_AVR_RTS);
snes_hirom(); snes_hirom();

View File

@@ -37,7 +37,6 @@
#define SHARED_MEM_TX_CMD_TERMINATE 0x06 #define SHARED_MEM_TX_CMD_TERMINATE 0x06
#define SHARED_MEM_TX_LOC_STATE 0x000000 #define SHARED_MEM_TX_LOC_STATE 0x000000
#define SHARED_MEM_TX_LOC_SIZE 0x000040
#define SHARED_MEM_TX_LOC_CMD 0x000001 #define SHARED_MEM_TX_LOC_CMD 0x000001
#define SHARED_MEM_TX_LOC_PAYLOAD 0x000002 #define SHARED_MEM_TX_LOC_PAYLOAD 0x000002
@@ -48,7 +47,6 @@
#define SHARED_MEM_RX_CMD_FILESEL 0x01 #define SHARED_MEM_RX_CMD_FILESEL 0x01
#define SHARED_MEM_RX_LOC_STATE 0x001000 #define SHARED_MEM_RX_LOC_STATE 0x001000
#define SHARED_MEM_RX_LOC_SIZE 0x000040
#define SHARED_MEM_RX_LOC_CMD 0x001001 #define SHARED_MEM_RX_LOC_CMD 0x001001
#define SHARED_MEM_RX_LOC_LEN 0x001002 #define SHARED_MEM_RX_LOC_LEN 0x001002
#define SHARED_MEM_RX_LOC_PAYLOAD 0x001003 #define SHARED_MEM_RX_LOC_PAYLOAD 0x001003
@@ -62,11 +60,6 @@
uint8_t shared_memory_scratchpad_region_save_helper(uint32_t addr);
void shared_memory_scratchpad_region_tx_save();
void shared_memory_scratchpad_region_tx_restore();
void shared_memory_scratchpad_region_rx_save();
void shared_memory_scratchpad_region_rx_restore();
void shared_memory_write(uint8_t cmd, uint8_t value); void shared_memory_write(uint8_t cmd, uint8_t value);
int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer); int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer);

View File

@@ -22,8 +22,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <avr/io.h> #include <avr/io.h>
#include <util/delay.h> /* for _delay_ms() */ #include <util/delay.h>
#include "config.h" #include "config.h"
#include "sram.h" #include "sram.h"
@@ -34,6 +33,7 @@
uint32_t addr_current = 0; uint32_t addr_current = 0;
uint32_t addr_stash = 0; uint32_t addr_stash = 0;
void system_init(void) void system_init(void)
{ {
/*-------------------------------------------------*/ /*-------------------------------------------------*/
@@ -47,17 +47,18 @@ void system_init(void)
| (1 << AVR_ADDR_SCK_PIN) | (1 << AVR_ADDR_SCK_PIN)
| (1 << AVR_ADDR_SER_PIN) | (1 << AVR_ADDR_SER_PIN)
| (1 << AVR_ADDR_LOAD_PIN) | (1 << AVR_ADDR_LOAD_PIN)
| (1 << AVR_ADDR_UP_PIN)); | (1 << AVR_ADDR_DOWN_PIN)
| (1 << AVR_ADDR_UP_PIN));
DDRC &= ~ ((1 << SNES_WR_PIN) DDRC &= ~ (1 << SNES_WR_PIN);
| (1 << AVR_BTLDR_EN_PIN));
PORTC &= ~((1 << AVR_ADDR_LATCH_PIN) PORTC &= ~((1 << AVR_ADDR_LATCH_PIN)
| (1 << AVR_ADDR_SCK_PIN) | (1 << AVR_ADDR_SCK_PIN)
| (1 << SNES_WR_PIN)); | (1 << SNES_WR_PIN));
PORTC |= ( (1 << AVR_ADDR_UP_PIN) PORTC |= ( (1 << AVR_ADDR_DOWN_PIN)
| (1 << AVR_ADDR_UP_PIN)
| (1 << AVR_ADDR_LOAD_PIN)); | (1 << AVR_ADDR_LOAD_PIN));
//| (1 << SNES_WR_PIN)); //| (1 << SNES_WR_PIN));
@@ -91,22 +92,23 @@ void system_init(void)
} }
void sreg_set(uint32_t addr) void sreg_set(uint32_t addr)
{ {
uint8_t i = 24; uint8_t i = 24;
debug_P(DEBUG_SREG, PSTR("sreg_set: addr=0x%08lx"),addr); debug(DEBUG_SRAM,"sreg_set: addr=0x%08lx\n",addr);
while(i--) { while(i--) {
if ((addr & ( 1L << i))){ if ((addr & ( 1L << i))){
debug_P(DEBUG_SREG, PSTR("1")); debug(DEBUG_SRAM,"1");
AVR_ADDR_SER_PORT |= ( 1 << AVR_ADDR_SER_PIN); AVR_ADDR_SER_PORT |= ( 1 << AVR_ADDR_SER_PIN);
} else { } else {
AVR_ADDR_SER_PORT &= ~( 1 << AVR_ADDR_SER_PIN); AVR_ADDR_SER_PORT &= ~( 1 << AVR_ADDR_SER_PIN);
debug_P(DEBUG_SREG, PSTR("0")); debug(DEBUG_SRAM,"0");
} }
AVR_ADDR_SCK_PORT |= (1 << AVR_ADDR_SCK_PIN); AVR_ADDR_SCK_PORT |= (1 << AVR_ADDR_SCK_PIN);
AVR_ADDR_SCK_PORT &= ~(1 << AVR_ADDR_SCK_PIN); AVR_ADDR_SCK_PORT &= ~(1 << AVR_ADDR_SCK_PIN);
} }
debug_P(DEBUG_SREG, PSTR("\n")); debug(DEBUG_SRAM,"\n");
AVR_ADDR_LATCH_PORT |= (1 << AVR_ADDR_LATCH_PIN); AVR_ADDR_LATCH_PORT |= (1 << AVR_ADDR_LATCH_PIN);
AVR_ADDR_LATCH_PORT &= ~(1 << AVR_ADDR_LATCH_PIN); AVR_ADDR_LATCH_PORT &= ~(1 << AVR_ADDR_LATCH_PIN);
@@ -127,7 +129,7 @@ inline void sram_bulk_addr_restore()
void sram_bulk_read_start(uint32_t addr) void sram_bulk_read_start(uint32_t addr)
{ {
debug_P(DEBUG_SRAM, PSTR("sram_bulk_read_start: addr=0x%08lx\n\r"), addr); debug(DEBUG_SRAM,"sram_bulk_read_start: addr=0x%08lx\n\r", addr);
addr_current = addr; addr_current = addr;
@@ -173,7 +175,7 @@ inline uint8_t sram_bulk_read(void)
void sram_bulk_read_end(void) void sram_bulk_read_end(void)
{ {
debug_P(DEBUG_SRAM, PSTR("sram_bulk_read_end:\n")); debug(DEBUG_SRAM,"sram_bulk_read_end:\n");
AVR_RD_PORT |= (1 << AVR_RD_PIN); AVR_RD_PORT |= (1 << AVR_RD_PIN);
AVR_CS_PORT |= (1 << AVR_CS_PIN); AVR_CS_PORT |= (1 << AVR_CS_PIN);
@@ -183,7 +185,7 @@ void sram_bulk_read_end(void)
uint8_t sram_read(uint32_t addr) uint8_t sram_read(uint32_t addr)
{ {
uint8_t byte; uint8_t byte;
debug_P(DEBUG_SRAM_RAW, PSTR("sram_read: addr=0x%08lx\n\r"), addr); debug(DEBUG_SRAM_RAW,"sram_read: addr=0x%08lx\n\r", addr);
avr_data_in(); avr_data_in();
@@ -215,7 +217,7 @@ uint8_t sram_read(uint32_t addr)
void sram_bulk_write_start(uint32_t addr) void sram_bulk_write_start(uint32_t addr)
{ {
debug_P(DEBUG_SRAM, PSTR("sram_bulk_write_start: addr=0x%08lx\n\r"), addr); debug(DEBUG_SRAM,"sram_bulk_write_start: addr=0x%08lx\n\r", addr);
avr_data_out(); avr_data_out();
@@ -243,7 +245,7 @@ inline void sram_bulk_write( uint8_t data)
void sram_bulk_write_end(void) void sram_bulk_write_end(void)
{ {
debug_P(DEBUG_SRAM, PSTR("sram_bulk_write_end:")); debug(DEBUG_SRAM,"sram_bulk_write_end:");
AVR_WR_PORT |= (1 << AVR_WR_PIN); AVR_WR_PORT |= (1 << AVR_WR_PIN);
AVR_CS_PORT |= (1 << AVR_CS_PIN); AVR_CS_PORT |= (1 << AVR_CS_PIN);
avr_data_in(); avr_data_in();
@@ -252,7 +254,7 @@ void sram_bulk_write_end(void)
void sram_write(uint32_t addr, uint8_t data) void sram_write(uint32_t addr, uint8_t data)
{ {
debug_P(DEBUG_SRAM_RAW, PSTR("sram_write: addr=0x%08lx data=%x\n\r"), addr, data); debug(DEBUG_SRAM_RAW,"sram_write: addr=0x%08lx data=%x\n\r", addr, data);
avr_data_out(); avr_data_out();
@@ -281,13 +283,12 @@ void sram_write(uint32_t addr, uint8_t data)
} }
void sram_bulk_copy_from_buffer(uint32_t addr, uint8_t * src, uint32_t len) void sram_bulk_copy(uint32_t addr, uint8_t * src, uint32_t len)
{ {
uint32_t i; uint32_t i;
uint8_t *ptr = src; uint8_t *ptr = src;
debug_P(DEBUG_SRAM, PSTR("sram_bulk_copy_from_buffer: addr=0x%08lx src=0x%p len=%li\n\r"), debug(DEBUG_SRAM,"sram_copy: addr=0x%08lx src=0x%p len=%li\n\r", addr,src,len);
addr, src, len);
sram_bulk_write_start(addr); sram_bulk_write_start(addr);
for (i = addr; i < (addr + len); i++){ for (i = addr; i < (addr + len); i++){
sram_bulk_write(*ptr++); sram_bulk_write(*ptr++);
@@ -296,13 +297,12 @@ void sram_bulk_copy_from_buffer(uint32_t addr, uint8_t * src, uint32_t len)
sram_bulk_write_end(); sram_bulk_write_end();
} }
void sram_bulk_copy_into_buffer(uint32_t addr, uint8_t * dst, uint32_t len) void sram_bulk_read_buffer(uint32_t addr, uint8_t * dst, uint32_t len)
{ {
uint32_t i; uint32_t i;
uint8_t *ptr = dst; uint8_t *ptr = dst;
debug_P(DEBUG_SRAM, PSTR("sram_bulk_copy_into_buffer: addr=0x%08lx dst=0x%p len=%li\n\r"), debug(DEBUG_SRAM,"sram_bulk_read_buffer: addr=0x%08lx dst=0x%p len=%li\n\r", addr,dst,len);
addr, dst, len);
sram_bulk_read_start(addr); sram_bulk_read_start(addr);
for (i = addr; i < (addr + len); i++) { for (i = addr; i < (addr + len); i++) {
*ptr = sram_bulk_read(); *ptr = sram_bulk_read();
@@ -314,11 +314,11 @@ void sram_bulk_copy_into_buffer(uint32_t addr, uint8_t * dst, uint32_t len)
void sram_bulk_set(uint32_t addr, uint32_t len,uint8_t value){ void sram_bulk_set(uint32_t addr, uint32_t len,uint8_t value){
uint32_t i; uint32_t i;
debug_P(DEBUG_SRAM, PSTR("sram_bulk_set: addr=0x%08lx len=%li\n\r"), addr,len); debug(DEBUG_SRAM,"sram_bulk_set: addr=0x%08lx len=%li\n\r", addr,len);
sram_bulk_write_start(addr); sram_bulk_write_start(addr);
for (i = addr; i < (addr + len); i++) { for (i = addr; i < (addr + len); i++) {
if (0 == i % 0xfff) if (0 == i % 0xfff)
debug_P(DEBUG_SRAM, PSTR("sram_bulk_set: addr=0x%08lx\n\r"), i); debug(DEBUG_SRAM,"sram_bulk_set: addr=0x%08lx\n\r", i);
sram_bulk_write(value); sram_bulk_write(value);
sram_bulk_write_next(); sram_bulk_write_next();
} }

View File

@@ -40,6 +40,14 @@
#define avr_data_out() (AVR_DATA_DIR = 0xff) #define avr_data_out() (AVR_DATA_DIR = 0xff)
#define LED_PORT PORTC
#define LED_DIR DDRC
#define LED_PIN PC7
#define led_on() ((LED_PORT &=~ (1 << LED_PIN)),\
(LED_DIR &=~ (1 << LED_PIN)))
#define led_off() ((LED_PORT &=~ (1 << LED_PIN)),\
(LED_DIR |= (1 << LED_PIN)))
/* ---------------------------- PORT B ---------------------------- */ /* ---------------------------- PORT B ---------------------------- */
@@ -77,6 +85,17 @@
#define snes_irq_off() (SNES_IRQ_DIR &= ~(1 << SNES_IRQ_PIN)) #define snes_irq_off() (SNES_IRQ_DIR &= ~(1 << SNES_IRQ_PIN))
#define snes_irq_lo() (SNES_IRQ_PORT &= ~(1 << SNES_IRQ_PIN)) #define snes_irq_lo() (SNES_IRQ_PORT &= ~(1 << SNES_IRQ_PIN))
#define SNES_RESET_PORT PORTB
#define SNES_RESET_DIR DDRB
#define SNES_RESET_PIN PB4
#define snes_reset_on() (SNES_RESET_DIR |= (1 << SNES_RESET_PIN))
#define snes_reset_hi() (SNES_RESET_PORT |= (1 << SNES_RESET_PIN))
#define snes_reset_off() (SNES_RESET_DIR &= ~(1 << SNES_RESET_PIN))
#define snes_reset_lo() (SNES_RESET_PORT &= ~(1 << SNES_RESET_PIN))
/* ---------------------------- PORT C ---------------------------- */ /* ---------------------------- PORT C ---------------------------- */
@@ -110,12 +129,12 @@
#define counter_load() ((AVR_ADDR_LOAD_PORT &= ~(1 << AVR_ADDR_LOAD_PIN)),\ #define counter_load() ((AVR_ADDR_LOAD_PORT &= ~(1 << AVR_ADDR_LOAD_PIN)),\
(AVR_ADDR_LOAD_PORT |= (1 << AVR_ADDR_LOAD_PIN))) (AVR_ADDR_LOAD_PORT |= (1 << AVR_ADDR_LOAD_PIN)))
#define AVR_BTLDR_EN_PORT PORTC #define AVR_ADDR_DOWN_PORT PORTC
#define AVR_BTLDR_EN_DIR DDRC #define AVR_ADDR_DOWN_DIR DDRC
#define AVR_BTLDR_EN_PIN PC1 #define AVR_ADDR_DOWN_PIN PC1
#define btldr_down() ((AVR_BTLDR_EN_PORT &= ~(1 << AVR_BTLDR_EN_PIN)),\ #define counter_down() ((AVR_ADDR_DOWN_PORT &= ~(1 << AVR_ADDR_DOWN_PIN)),\
(AVR_BTLDR_EN_PORT |= (1 << AVR_BTLDR_EN_PIN))) (AVR_ADDR_DOWN_PORT |= (1 << AVR_ADDR_DOWN_PIN)))
#define AVR_ADDR_UP_PORT PORTC #define AVR_ADDR_UP_PORT PORTC
#define AVR_ADDR_UP_DIR DDRC #define AVR_ADDR_UP_DIR DDRC
@@ -128,16 +147,6 @@
#define SNES_WR_DIR DDRC #define SNES_WR_DIR DDRC
#define SNES_WR_PIN PC3 #define SNES_WR_PIN PC3
#define LED_PORT PORTC
#define LED_DIR DDRC
#define LED_PIN PC7
#define led_on() ((LED_PORT &=~ (1 << LED_PIN)),\
(LED_DIR &=~ (1 << LED_PIN)))
#define led_off() ((LED_PORT &=~ (1 << LED_PIN)),\
(LED_DIR |= (1 << LED_PIN)))
/* ---------------------------- PORT D ---------------------------- */ /* ---------------------------- PORT D ---------------------------- */
#define AVR_SNES_PORT PORTD #define AVR_SNES_PORT PORTD
@@ -168,27 +177,6 @@
#define snes_wr_enable() (SNES_WR_EN_PORT |= (1 << SNES_WR_EN_PIN)) #define snes_wr_enable() (SNES_WR_EN_PORT |= (1 << SNES_WR_EN_PIN))
#define SNES_RESET_PORT PORTD
#define SNES_RESET_DIR DDRD
#define SNES_RESET_PIN PD3
#define SNES_RESET_INP PIND
#define snes_reset_on() (SNES_RESET_DIR |= (1 << SNES_RESET_PIN))
#define snes_reset_hi() (SNES_RESET_PORT |= (1 << SNES_RESET_PIN))
#define snes_reset_off() (SNES_RESET_DIR &= ~(1 << SNES_RESET_PIN))
#define snes_reset_lo() (SNES_RESET_PORT &= ~(1 << SNES_RESET_PIN))
#define snes_reset_test() ((SNES_RESET_INP & (1 << SNES_RESET_PIN)) == 0)
#define MMC_PORT PORTB
#define MMC_DIR DDRB
#define MMC_MISO_PIN PB6
#define MMC_MOSI_PIN PB5
#define MMC_SCK_PIN PB7
#define MMC_CS_PIN PB4
@@ -209,9 +197,8 @@ inline void sram_bulk_write_next(void);
inline void sram_bulk_write_end(void); inline void sram_bulk_write_end(void);
void sram_bulk_write(uint8_t data); void sram_bulk_write(uint8_t data);
void sram_bulk_copy_from_buffer(uint32_t addr, uint8_t * src, uint32_t len); void sram_bulk_copy(uint32_t addr, uint8_t * src, uint32_t len);
void sram_bulk_copy_into_buffer(uint32_t addr, uint8_t * dst, uint32_t len); void sram_bulk_read_buffer(uint32_t addr, uint8_t * dst, uint32_t len);
void sram_bulk_set(uint32_t addr, uint32_t len,uint8_t value); void sram_bulk_set(uint32_t addr, uint32_t len,uint8_t value);
inline void sram_bulk_addr_save(); inline void sram_bulk_addr_save();

View File

@@ -1,428 +0,0 @@
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert@users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.7 //
AVR_ADDR_DIR sram.h 103;" d
AVR_ADDR_DOWN_DIR sram.h 133;" d
AVR_ADDR_DOWN_PIN sram.h 134;" d
AVR_ADDR_DOWN_PORT sram.h 132;" d
AVR_ADDR_LATCH_DIR sram.h 105;" d
AVR_ADDR_LATCH_PIN sram.h 106;" d
AVR_ADDR_LATCH_PORT sram.h 104;" d
AVR_ADDR_LOAD_DIR sram.h 126;" d
AVR_ADDR_LOAD_PIN sram.h 127;" d
AVR_ADDR_LOAD_PORT sram.h 125;" d
AVR_ADDR_PORT sram.h 102;" d
AVR_ADDR_SCK_DIR sram.h 112;" d
AVR_ADDR_SCK_PIN sram.h 113;" d
AVR_ADDR_SCK_PORT sram.h 111;" d
AVR_ADDR_SER_DIR sram.h 119;" d
AVR_ADDR_SER_PIN sram.h 120;" d
AVR_ADDR_SER_PORT sram.h 118;" d
AVR_ADDR_UP_DIR sram.h 140;" d
AVR_ADDR_UP_PIN sram.h 141;" d
AVR_ADDR_UP_PORT sram.h 139;" d
AVR_CS_DIR sram.h 71;" d
AVR_CS_PIN sram.h 72;" d
AVR_CS_PORT sram.h 70;" d
AVR_DATA_DIR sram.h 35;" d
AVR_DATA_PIN sram.h 36;" d
AVR_DATA_PORT sram.h 34;" d
AVR_DIR sram.h 55;" d
AVR_PORT sram.h 54;" d
AVR_RD_DIR sram.h 57;" d
AVR_RD_PIN sram.h 58;" d
AVR_RD_PORT sram.h 56;" d
AVR_SNES_DIR sram.h 153;" d
AVR_SNES_PORT sram.h 152;" d
AVR_SNES_SW_DIR sram.h 155;" d
AVR_SNES_SW_PIN sram.h 156;" d
AVR_SNES_SW_PORT sram.h 154;" d
AVR_WR_DIR sram.h 64;" d
AVR_WR_PIN sram.h 65;" d
AVR_WR_PORT sram.h 63;" d
CR uart.h 25;" d
DEBOUNCE timer.c 44;" d file:
DEBUG config.h 25;" d
DEBUG_CRC config.h 31;" d
DEBUG_SHM config.h 32;" d
DEBUG_SRAM config.h 28;" d
DEBUG_SRAM_RAW config.h 29;" d
DEBUG_SREG config.h 30;" d
DEBUG_USB config.h 26;" d
DEBUG_USB_TRANS config.h 27;" d
FILE_MKDIR config.h 48;" d
FILE_RM config.h 49;" d
FILE_WRITE config.h 47;" d
Fat fat.h /^ extern struct Fat{ \/\/ fat daten (1.cluster, root-dir, dir usw.)$/;" s
File fat.h /^ extern struct File{ \/\/ datei infos$/;" s
HI_LOROM_SW_DIR sram.h 166;" d
HI_LOROM_SW_PIN sram.h 167;" d
HI_LOROM_SW_PORT sram.h 165;" d
INBYTE rle.c 44;" d file:
ISR timer.c /^ISR (SIG_OUTPUT_COMPARE1A)$/;" f
ISR uart.c /^ISR(USART0_RX_vect)$/;" f
LED_DIR sram.h 44;" d
LED_PIN sram.h 45;" d
LED_PORT sram.h 43;" d
MAX_CLUSTERS_IN_ROW fat.h 11;" d
MMC_CLK mmc.h 21;" d
MMC_CS mmc.h 18;" d
MMC_DI mmc.h 20;" d
MMC_DO mmc.h 19;" d
MMC_READ mmc.h 15;" d
MMC_READ mmc.h 24;" d
MMC_REG mmc.h 16;" d
MMC_REG mmc.h 25;" d
MMC_WRITE mmc.h 14;" d
MMC_WRITE mmc.h 23;" d
OCR1A timer.c 34;" d file:
OUTBYTE rle.c 54;" d file:
OVER_WRITE fat.h 10;" d
PROGMEM loader.c /^const char _rom[ROM_BUFFER_SIZE] PROGMEM = {$/;" v
REQ_STATUS_AVR config.h 40;" d
REQ_STATUS_BULK_NEXT config.h 37;" d
REQ_STATUS_BULK_UPLOAD config.h 36;" d
REQ_STATUS_CRC config.h 38;" d
REQ_STATUS_IDLE config.h 34;" d
REQ_STATUS_SNES config.h 39;" d
REQ_STATUS_UPLOAD config.h 35;" d
ROM_BUFFER_SIZE loader.h 5;" d
ROM_HUFFMAN_SIZE loader.h 6;" d
ROM_RLE_SIZE loader.h 7;" d
RUNCHAR rle.c 33;" d file:
SHARED_IRQ_HANDLER_HI shared_memory.h 59;" d
SHARED_IRQ_HANDLER_LO shared_memory.h 58;" d
SHARED_IRQ_LOC_HI shared_memory.h 55;" d
SHARED_IRQ_LOC_LO shared_memory.h 54;" d
SHARED_MEM_RX_AVR_ACK shared_memory.h 43;" d
SHARED_MEM_RX_AVR_RTS shared_memory.h 44;" d
SHARED_MEM_RX_CMD_FILESEL shared_memory.h 47;" d
SHARED_MEM_RX_CMD_PRINFT shared_memory.h 46;" d
SHARED_MEM_RX_LOC_CMD shared_memory.h 50;" d
SHARED_MEM_RX_LOC_LEN shared_memory.h 51;" d
SHARED_MEM_RX_LOC_PAYLOAD shared_memory.h 52;" d
SHARED_MEM_RX_LOC_STATE shared_memory.h 49;" d
SHARED_MEM_SWITCH_DELAY shared_memory.h 26;" d
SHARED_MEM_SWITCH_IRQ shared_memory.h 25;" d
SHARED_MEM_TX_CMD_BANK_COUNT shared_memory.h 31;" d
SHARED_MEM_TX_CMD_BANK_CURRENT shared_memory.h 32;" d
SHARED_MEM_TX_CMD_TERMINATE shared_memory.h 37;" d
SHARED_MEM_TX_CMD_UPLOAD_END shared_memory.h 35;" d
SHARED_MEM_TX_CMD_UPLOAD_PROGESS shared_memory.h 36;" d
SHARED_MEM_TX_CMD_UPLOAD_START shared_memory.h 34;" d
SHARED_MEM_TX_LOC_CMD shared_memory.h 40;" d
SHARED_MEM_TX_LOC_PAYLOAD shared_memory.h 41;" d
SHARED_MEM_TX_LOC_STATE shared_memory.h 39;" d
SHARED_MEM_TX_SNES_ACK shared_memory.h 28;" d
SHARED_MEM_TX_SNES_RTS shared_memory.h 29;" d
SMALL_FILE_SYSTEM config.h 50;" d
SMALL_FILE_SYSTEM fat.h 8;" d
SNES_IRQ_DIR sram.h 78;" d
SNES_IRQ_PIN sram.h 79;" d
SNES_IRQ_PORT sram.h 77;" d
SNES_RESET_DIR sram.h 89;" d
SNES_RESET_PIN sram.h 90;" d
SNES_RESET_PORT sram.h 88;" d
SNES_WR_DIR sram.h 147;" d
SNES_WR_EN_DIR sram.h 173;" d
SNES_WR_EN_PIN sram.h 174;" d
SNES_WR_EN_PORT sram.h 172;" d
SNES_WR_PIN sram.h 148;" d
SNES_WR_PORT sram.h 146;" d
SPI_Mode mmc.h 12;" d
TRANSFER_BUFFER_SIZE config.h 45;" d
USB_AVR_RESET requests.h 40;" d
USB_BULK_UPLOAD_ADDR requests.h 35;" d
USB_BULK_UPLOAD_END requests.h 37;" d
USB_BULK_UPLOAD_INIT requests.h 34;" d
USB_BULK_UPLOAD_NEXT requests.h 36;" d
USB_CFG_CHECK_CRC usbconfig.h 72;" d
USB_CFG_CHECK_DATA_TOGGLING usbconfig.h 211;" d
USB_CFG_CLOCK_KHZ usbconfig.h 65;" d
USB_CFG_DESCR_PROPS_CONFIGURATION usbconfig.h 346;" d
USB_CFG_DESCR_PROPS_DEVICE usbconfig.h 345;" d
USB_CFG_DESCR_PROPS_HID usbconfig.h 352;" d
USB_CFG_DESCR_PROPS_HID_REPORT usbconfig.h 353;" d
USB_CFG_DESCR_PROPS_STRINGS usbconfig.h 347;" d
USB_CFG_DESCR_PROPS_STRING_0 usbconfig.h 348;" d
USB_CFG_DESCR_PROPS_STRING_PRODUCT usbconfig.h 350;" d
USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER usbconfig.h 351;" d
USB_CFG_DESCR_PROPS_STRING_VENDOR usbconfig.h 349;" d
USB_CFG_DESCR_PROPS_UNKNOWN usbconfig.h 354;" d
USB_CFG_DEVICE_CLASS usbconfig.h 266;" d
USB_CFG_DEVICE_ID usbconfig.h 231;" d
USB_CFG_DEVICE_NAME usbconfig.h 251;" d
USB_CFG_DEVICE_NAME_LEN usbconfig.h 252;" d
USB_CFG_DEVICE_SUBCLASS usbconfig.h 267;" d
USB_CFG_DEVICE_VERSION usbconfig.h 238;" d
USB_CFG_DMINUS_BIT usbconfig.h 52;" d
USB_CFG_DPLUS_BIT usbconfig.h 56;" d
USB_CFG_EP3_NUMBER usbconfig.h 106;" d
USB_CFG_HAVE_FLOWCONTROL usbconfig.h 161;" d
USB_CFG_HAVE_INTRIN_ENDPOINT usbconfig.h 95;" d
USB_CFG_HAVE_INTRIN_ENDPOINT3 usbconfig.h 100;" d
USB_CFG_HAVE_MEASURE_FRAME_LENGTH usbconfig.h 219;" d
USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH usbconfig.h 279;" d
USB_CFG_IMPLEMENT_FN_READ usbconfig.h 149;" d
USB_CFG_IMPLEMENT_FN_WRITE usbconfig.h 144;" d
USB_CFG_IMPLEMENT_FN_WRITEOUT usbconfig.h 155;" d
USB_CFG_IMPLEMENT_HALT usbconfig.h 116;" d
USB_CFG_INTERFACE_CLASS usbconfig.h 271;" d
USB_CFG_INTERFACE_PROTOCOL usbconfig.h 273;" d
USB_CFG_INTERFACE_SUBCLASS usbconfig.h 272;" d
USB_CFG_INTR_POLL_INTERVAL usbconfig.h 130;" d
USB_CFG_IOPORTNAME usbconfig.h 48;" d
USB_CFG_IS_SELF_POWERED usbconfig.h 135;" d
USB_CFG_LONG_TRANSFERS usbconfig.h 166;" d
USB_CFG_MAX_BUS_POWER usbconfig.h 139;" d
USB_CFG_SUPPRESS_INTR_CODE usbconfig.h 122;" d
USB_CFG_VENDOR_ID usbconfig.h 226;" d
USB_CFG_VENDOR_NAME usbconfig.h 241;" d
USB_CFG_VENDOR_NAME_LEN usbconfig.h 242;" d
USB_COUNT_SOF usbconfig.h 187;" d
USB_CRC requests.h 31;" d
USB_CRC_ADDR requests.h 32;" d
USB_CRC_CHECK config.h 43;" d
USB_DOWNLOAD_ADDR requests.h 29;" d
USB_DOWNLOAD_INIT requests.h 28;" d
USB_MAX_TRANS config.h 42;" d
USB_MODE_AVR requests.h 39;" d
USB_MODE_SNES requests.h 38;" d
USB_UPLOAD_ADDR requests.h 26;" d
USB_UPLOAD_INIT requests.h 25;" d
WGM12 timer.c 38;" d file:
WRITE fat.h 9;" d
XTAL timer.c 42;" d file:
_FAT_H fat.h 4;" d
_FILE_H file.h 6;" d
_HARDWARE_H hardware.h 7;" d
_MMC_H mmc.h 9;" d
__COMMAND_H__ command.h 23;" d
__CONFIH_H__ config.h 22;" d
__CRC_H__ crc.h 23;" d
__DEBUG_H__ debug.h 24;" d
__DUMP_H__ dump.h 23;" d
__FIFO_H__ fifo.h 21;" d
__FIFO_H__ loader.h 3;" d
__INFO_H__ info.h 24;" d
__REQUESTS_H__ requests.h 23;" d
__RLE_H__ rle.h 22;" d
__SHARED_MEMORY_H__ shared_memory.h 22;" d
__SRAM_H__ sram.h 24;" d
__TESTING_H__ testing.h 23;" d
__TIMER_H__ timer.h 22;" d
__UART_H__ uart.h 23;" d
__USB_BULK_H__ usb_bulk.h 23;" d
__WATCHDOG_H__ watchdog.h 27;" d
__usbconfig_h_included__ usbconfig.h 34;" d
_inline_fifo_get fifo.h /^static inline uint8_t _inline_fifo_get(fifo_t * f)$/;" f
_inline_fifo_put fifo.h /^static inline uint8_t _inline_fifo_put(fifo_t * f, const uint8_t data)$/;" f
adc_int uart.c /^ uint8_t adc_int:1;$/;" m struct:__anon2 file:
addr main.c /^uint32_t addr;$/;" v
addr_current sram.c /^uint32_t addr_current = 0;$/;" v
addr_stash sram.c /^uint32_t addr_stash = 0;$/;" v
attrib fat.h /^ unsigned char attrib; \/\/ 11,1 datei Attribut: 8=value name, 32=datei, 16=Verzeichniss, 15=linux kleingeschrieben eintrag$/;" m struct:File
avr_addr_latch_hi sram.h 108;" d
avr_addr_latch_lo sram.h 109;" d
avr_addr_sck_hi sram.h 115;" d
avr_addr_sck_lo sram.h 116;" d
avr_addr_ser_hi sram.h 122;" d
avr_addr_ser_lo sram.h 123;" d
avr_bus_active sram.h 158;" d
avr_cs_hi sram.h 74;" d
avr_cs_lo sram.h 75;" d
avr_data_in sram.h 38;" d
avr_data_out sram.h 41;" d
avr_rd_hi sram.h 60;" d
avr_rd_lo sram.h 61;" d
avr_wr_hi sram.h 67;" d
avr_wr_lo sram.h 68;" d
boot_startup_rom main.c /^void boot_startup_rom()$/;" f
bufferDirty fat.h /^ unsigned char bufferDirty; \/\/ puffer wurde beschrieben, sector muss geschrieben werden bevor er neu geladen wird$/;" m struct:Fat
cntOfBytes fat.h /^ unsigned int cntOfBytes; \/\/ -nicht direkt aus dem dateisystem- zäht geschriebene bytes eines sektors$/;" m struct:File
count fifo.h /^ uint8_t volatile count; \/\/ # Zeichen im Puffer$/;" m struct:__anon1
counter_down sram.h 136;" d
counter_load sram.h 129;" d
counter_up sram.h 143;" d
crc main.c /^uint16_t crc = 0;$/;" v
crc_check_bulk_memory crc.c /^uint16_t crc_check_bulk_memory(uint32_t bottom_addr, uint32_t top_addr, uint32_t bank_size)$/;" f
crc_check_memory_range crc.c /^uint16_t crc_check_memory_range(uint32_t start_addr, uint32_t size,uint8_t *buffer)$/;" f
crc_xmodem_update crc.c /^uint16_t crc_xmodem_update(uint16_t crc, uint8_t data)$/;" f
currentSectorNr fat.h /^ unsigned long int currentSectorNr;\/\/ aktuell geladener Sektor (in sector) \/\/beschleunigt wenn z.b 2* 512 byte puffer vorhanden, oder bei fat operationen im gleichen sektor$/;" m struct:Fat
dataDirSec fat.h /^ unsigned long int dataDirSec; \/\/ Sektor nr data area $/;" m struct:Fat
data_buffer main.c /^uint8_t data_buffer[4];$/;" v
debug debug.c /^void debug(int level, char* format, ...) {$/;" f
debug debug.h 34;" d
debug_level main.c /^uint8_t debug_level = (DEBUG | DEBUG_USB | DEBUG_CRC);$/;" v
dir fat.h /^ unsigned long int dir; \/\/ Direktory zeiger rootDir=='0' sonst(1.Cluster des dir; start auf root)$/;" m struct:Fat
do_crc crc.c /^uint16_t do_crc(uint8_t * data, uint16_t size)$/;" f
do_crc_update crc.c /^uint16_t do_crc_update(uint16_t crc, uint8_t * data, uint16_t size)$/;" f
dump_memory dump.c /^void dump_memory(uint32_t bottom_addr, uint32_t top_addr)$/;" f
dump_packet dump.c /^void dump_packet(uint32_t addr, uint32_t len, uint8_t * packet)$/;" f
endSectors fat.h /^ unsigned long int endSectors; $/;" m struct:Fat
fat fat.c /^struct Fat fat; \/\/ wichtige daten\/variablen der fat$/;" v typeref:struct:Fat
fatSec fat.h /^ unsigned long int fatSec; \/\/ Sektor nr fat area$/;" m struct:Fat
fatType fat.h /^ unsigned char fatType; \/\/ fat16 oder fat32 (16 oder 32)$/;" m struct:Fat
fat_cd fat.c /^unsigned char fat_cd(char name[]){$/;" f
fat_clustToSec fat.c /^unsigned long int fat_clustToSec(unsigned long int clust){$/;" f
fat_delClusterChain fat.c /^void fat_delClusterChain(unsigned long int startCluster){$/;" f
fat_getFatChainClustersInRow fat.c /^void fat_getFatChainClustersInRow(unsigned long int offsetCluster){$/;" f
fat_getFreeClustersInRow fat.c /^void fat_getFreeClustersInRow(unsigned long int offsetCluster){$/;" f
fat_getFreeRowOfCluster fat.c /^unsigned char fat_getFreeRowOfCluster(unsigned long secStart){$/;" f
fat_getFreeRowOfDir fat.c /^void fat_getFreeRowOfDir(unsigned long int dir){$/;" f
fat_getNextCluster fat.c /^unsigned long int fat_getNextCluster(unsigned long int oneCluster){ $/;" f
fat_initfat fat.c /^unsigned char fat_initfat(void){ $/;" f
fat_loadFatData fat.c /^unsigned char fat_loadFatData(unsigned long int sec){$/;" f
fat_loadFileDataFromCluster fat.c /^unsigned char fat_loadFileDataFromCluster(unsigned long int sec , char name[]){$/;" f
fat_loadFileDataFromDir fat.c /^unsigned char fat_loadFileDataFromDir(char name[]){ $/;" f
fat_loadRowOfSector fat.c /^unsigned char fat_loadRowOfSector(unsigned int row){$/;" f
fat_loadSector fat.c /^unsigned char fat_loadSector(unsigned long int sec){$/;" f
fat_makeFileEntry fat.c /^void fat_makeFileEntry(char name[],unsigned char attrib,unsigned long int length){$/;" f
fat_makeRowDataEntry fat.c /^void fat_makeRowDataEntry(unsigned int row,char name[],unsigned char attrib,unsigned long int cluster,unsigned long int length){$/;" f
fat_secToClust fat.c /^unsigned long int fat_secToClust(unsigned long int sec){$/;" f
fat_setCluster fat.c /^void fat_setCluster(unsigned long int cluster, unsigned long int content){ $/;" f
fat_setClusterChain fat.c /^void fat_setClusterChain(unsigned long int startCluster,unsigned int endCluster){$/;" f
fat_str fat.c /^char * fat_str(char *str){$/;" f
fat_writeSector fat.c /^unsigned char fat_writeSector(unsigned long int sec){ $/;" f
ffcd file.c /^unsigned char ffcd(char name[]){ $/;" f
ffcdLower file.c /^unsigned char ffcdLower(void){$/;" f
ffclose file.c /^unsigned char ffclose(void){$/;" f
ffls file.c /^void ffls(void){$/;" f
ffmkdir file.c /^void ffmkdir(char name[]){$/;" f
ffopen file.c /^unsigned char ffopen(char name[]){ $/;" f
ffread file.c /^inline unsigned char ffread(void){ $/;" f
ffrm file.c /^unsigned char ffrm(char name[]){ $/;" f
ffseek file.c /^void ffseek(unsigned long int offset){ $/;" f
ffwrite file.c /^inline void ffwrite(unsigned char c){$/;" f
ffwrites file.c /^inline void ffwrites(const char *s ){$/;" f
fifo_get_nowait fifo.c /^int fifo_get_nowait(fifo_t * f)$/;" f
fifo_get_wait fifo.c /^uint8_t fifo_get_wait(fifo_t * f)$/;" f
fifo_init fifo.c /^void fifo_init(fifo_t * f, uint8_t * buffer, const uint8_t size)$/;" f
fifo_put fifo.c /^uint8_t fifo_put(fifo_t * f, const uint8_t data)$/;" f
fifo_t fifo.h /^} fifo_t;$/;" t typeref:struct:__anon1
file fat.c /^struct File file; \/\/ wichtige dateibezogene daten\/variablen$/;" v typeref:struct:File
fileUpdate file.c /^void fileUpdate(void){$/;" f
firstCluster fat.h /^ unsigned long int firstCluster; \/\/ 20,2 \/26,2 datei 1.cluster hi,low(möglicherweise der einzige) (4-byte)$/;" m struct:File
info info.c /^void info(char* format, ...) {$/;" f
info info.c 34;" d file:
info info.h 34;" d
intflags uart.c /^} intflags;$/;" v typeref:struct:__anon2
irq_addr_hi shared_memory.c /^uint8_t irq_addr_hi;$/;" v
irq_addr_lo shared_memory.c /^uint8_t irq_addr_lo;$/;" v
lastCluster fat.h /^ unsigned long int lastCluster; \/\/ -nicht direkt aus dem dateisystem- letzter cluster der ersten kette$/;" m struct:File
led_off sram.h 49;" d
led_on sram.h 47;" d
length fat.h /^ unsigned long int length; \/\/ 28,4 datei Länge (4-byte)$/;" m struct:File
lsRowsOfClust file.c /^void lsRowsOfClust (unsigned long int start_sec){$/;" f
main main.c /^int main(void)$/;" f
mmc_disable mmc.h 38;" d
mmc_enable mmc.h 40;" d
mmc_init mmc.c /^uint8_t mmc_init()$/;" f
mmc_read_block mmc.c /^void mmc_read_block(uint8_t * cmd, uint8_t * Buffer, uint16_t Bytes)$/;" f
mmc_read_byte mmc.c /^uint8_t mmc_read_byte(void)$/;" f
mmc_read_cid mmc.c /^uint8_t mmc_read_cid(uint8_t * Buffer)$/;" f
mmc_read_csd mmc.c /^uint8_t mmc_read_csd(uint8_t * Buffer)$/;" f
mmc_read_sector mmc.c /^uint8_t mmc_read_sector(uint32_t addr, uint8_t * Buffer)$/;" f
mmc_write_byte mmc.c /^void mmc_write_byte(uint8_t Byte)$/;" f
mmc_write_command mmc.c /^uint8_t mmc_write_command(uint8_t * cmd)$/;" f
mmc_write_sector mmc.c /^uint8_t mmc_write_sector(uint32_t addr, uint8_t * Buffer)$/;" f
name fat.h /^ unsigned char name[13]; \/\/ 0,10 datei Name.ext (8.3 = max 11)(MUSS unsigned char weil E5)$/;" m struct:File
nop mmc.h 42;" d
pread fifo.h /^ uint8_t *pread; \/\/ Lesezeiger$/;" m struct:__anon1
prescaler timer.c /^uint16_t prescaler;$/;" v
pwrite fifo.h /^ uint8_t *pwrite; \/\/ Schreibzeiger$/;" m struct:__anon1
read2end fifo.h /^ uint8_t read2end, write2end; \/\/ # Zeichen bis zum Überlauf Lese-\/Schreibzeiger$/;" m struct:__anon1
read_buffer main.c /^uint8_t read_buffer[TRANSFER_BUFFER_SIZE];$/;" v
req_addr main.c /^uint32_t req_addr = 0;$/;" v
req_addr_end main.c /^uint32_t req_addr_end = 0;$/;" v
req_bank main.c /^uint8_t req_bank;$/;" v
req_bank_cnt main.c /^uint16_t req_bank_cnt;$/;" v
req_bank_size main.c /^uint32_t req_bank_size;$/;" v
req_percent main.c /^uint8_t req_percent;$/;" v
req_percent_last main.c /^uint8_t req_percent_last;$/;" v
req_size main.c /^uint32_t req_size;$/;" v
req_state main.c /^uint8_t req_state = REQ_STATUS_IDLE;$/;" v
rle_decode rle.c /^uint8_t rle_decode(PGM_VOID_P in_addr, int32_t in_len, uint32_t out_addr)$/;" f
rootDir fat.h /^ unsigned long int rootDir; \/\/ Sektor(f16)\/Cluster(f32) nr root directory$/;" m struct:Fat
row fat.h /^ unsigned char row; \/\/ reihe im sektor in der die datei infos stehen (reihe 0-15)$/;" m struct:File
rx_int uart.c /^ uint8_t rx_int:1;$/;" m struct:__anon2 file:
rx_remaining main.c /^uint8_t rx_remaining = 0;$/;" v
rxbuff uart.c /^volatile char rxbuff;$/;" v
scratchpad_cmd shared_memory.c /^uint8_t scratchpad_cmd;$/;" v
scratchpad_payload shared_memory.c /^uint8_t scratchpad_payload;$/;" v
scratchpad_state shared_memory.c /^uint8_t scratchpad_state;$/;" v
secPerClust fat.h /^ unsigned char secPerClust; \/\/ anzahl der sektoren pro cluster$/;" m struct:Fat
second timer.c /^uint16_t volatile second; \/\/ count seconds$/;" v
sector fat.h /^ unsigned char sector[512]; \/\/ der puffer für sektoren !$/;" m struct:Fat
seek fat.h /^ unsigned long int seek; \/\/ schreib position in der datei$/;" m struct:File
send_irq command.c /^void send_irq()$/;" f
send_reset command.c /^void send_reset()$/;" f
set_rom_mode command.c /^void set_rom_mode()$/;" f
shared_memory_irq_hook shared_memory.c /^void shared_memory_irq_hook()$/;" f
shared_memory_irq_restore shared_memory.c /^void shared_memory_irq_restore()$/;" f
shared_memory_read shared_memory.c /^int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer)$/;" f
shared_memory_scratchpad_tx_restore shared_memory.c /^void shared_memory_scratchpad_tx_restore()$/;" f
shared_memory_scratchpad_tx_save shared_memory.c /^void shared_memory_scratchpad_tx_save()$/;" f
shared_memory_write shared_memory.c /^void shared_memory_write(uint8_t cmd, uint8_t value)$/;" f
shared_memory_yield shared_memory.c /^void shared_memory_yield()$/;" f
size fifo.h /^ uint8_t size; \/\/ Puffer-Größe$/;" m struct:__anon1
snes_bus_active sram.h 162;" d
snes_hirom sram.h 169;" d
snes_irq_hi sram.h 83;" d
snes_irq_lo sram.h 86;" d
snes_irq_off sram.h 85;" d
snes_irq_on sram.h 82;" d
snes_lorom sram.h 170;" d
snes_reset_hi sram.h 94;" d
snes_reset_lo sram.h 97;" d
snes_reset_off sram.h 96;" d
snes_reset_on sram.h 93;" d
snes_wr_disable sram.h 176;" d
snes_wr_enable sram.h 178;" d
soft_reset watchdog.h 32;" d
sram_bulk_addr_restore sram.c /^inline void sram_bulk_addr_restore()$/;" f
sram_bulk_addr_save sram.c /^inline void sram_bulk_addr_save()$/;" f
sram_bulk_copy sram.c /^void sram_bulk_copy_from_buffer(uint32_t addr, uint8_t * src, uint32_t len)$/;" f
sram_bulk_read sram.c /^inline uint8_t sram_bulk_read(void)$/;" f
sram_bulk_copy_into_buffer sram.c /^void sram_bulk_copy_into_buffer(uint32_t addr, uint8_t * dst, uint32_t len)$/;" f
sram_bulk_read_end sram.c /^void sram_bulk_read_end(void)$/;" f
sram_bulk_read_next sram.c /^inline void sram_bulk_read_next(void)$/;" f
sram_bulk_read_start sram.c /^void sram_bulk_read_start(uint32_t addr)$/;" f
sram_bulk_set sram.c /^void sram_bulk_set(uint32_t addr, uint32_t len,uint8_t value){$/;" f
sram_bulk_write sram.c /^inline void sram_bulk_write( uint8_t data)$/;" f
sram_bulk_write_end sram.c /^void sram_bulk_write_end(void)$/;" f
sram_bulk_write_next sram.c /^inline void sram_bulk_write_next(void)$/;" f
sram_bulk_write_start sram.c /^void sram_bulk_write_start(uint32_t addr)$/;" f
sram_read sram.c /^uint8_t sram_read(uint32_t addr)$/;" f
sram_write sram.c /^void sram_write(uint32_t addr, uint8_t data)$/;" f
sreg_set sram.c /^void sreg_set(uint32_t addr)$/;" f
startSectors fat.h /^ unsigned long int startSectors; \/\/ der erste sektor in einer reihe (freie oder verkettete)$/;" m struct:Fat
sync_errors main.c /^uint16_t sync_errors = 0;$/;" v
system_init sram.c /^void system_init(void)$/;" f
test_bulk_read_write testing.c /^void test_bulk_read_write()$/;" f
test_crc testing.c /^void test_crc()$/;" f
test_non_zero_memory testing.c /^void test_non_zero_memory(uint32_t bottom_addr, uint32_t top_addr)$/;" f
test_read_write testing.c /^void test_read_write()$/;" f
test_sdcard testing.c /^void test_sdcard(void){$/;" f
timer_start timer.c /^void timer_start( void )$/;" f
timer_stop_int timer.c /^uint16_t timer_stop_int(void)$/;" f
tmr_int uart.c /^ uint8_t tmr_int:1;$/;" m struct:__anon2 file:
tx_buffer main.c /^uint8_t tx_buffer[32];$/;" v
tx_remaining main.c /^uint8_t tx_remaining = 0;$/;" v
uart_init uart.c /^void uart_init(void)$/;" f
uart_putc uart.c /^void uart_putc(uint8_t c)$/;" f
uart_puts uart.c /^void uart_puts(const char *s)$/;" f
uart_puts_P uart.c /^void uart_puts_P(PGM_P s)$/;" f
uart_stdout uart.c /^FILE uart_stdout = FDEV_SETUP_STREAM(uart_stream, NULL, _FDEV_SETUP_WRITE);$/;" v
uart_stream uart.c /^static int uart_stream(char c, FILE * stream)$/;" f file:
uint timer.c 47;" d file:
uint8_t timer.c 46;" d file:
usbFunctionRead usb_bulk.c /^uint8_t usbFunctionRead(uint8_t * data, uint8_t len)$/;" f
usbFunctionSetup main.c /^usbMsgLen_t usbFunctionSetup(uchar data[8])$/;" f
usbFunctionWrite usb_bulk.c /^uint8_t usbFunctionWrite(uint8_t * data, uint8_t len)$/;" f
usb_connect main.c /^void usb_connect()$/;" f
wdt_init watchdog.c /^void wdt_init(void)$/;" f
write2end fifo.h /^ uint8_t read2end, write2end; \/\/ # Zeichen bis zum Überlauf Lese-\/Schreibzeiger$/;" m struct:__anon1

View File

@@ -1,5 +1,3 @@
/* /*
* ===================================================================================== * =====================================================================================
* *
@@ -22,6 +20,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <util/delay.h> #include <util/delay.h>
@@ -30,8 +29,15 @@
#include "sram.h" #include "sram.h"
#include "debug.h" #include "debug.h"
#include "crc.h" #include "crc.h"
#include "config.h"
#include "info.h" #include "info.h"
#include "mmc.h"
#include "fat.h"
#include "file.h"
#include "dir.h"
void test_read_write() void test_read_write()
{ {
@@ -45,7 +51,7 @@ void test_read_write()
} }
addr = 0x000000; addr = 0x000000;
while (addr++ <= 0x0000ff) { while (addr++ <= 0x0000ff) {
info_P(PSTR("read addr=0x%08lx %x\n"), addr, sram_read(addr)); info("read addr=0x%08lx %x\n", addr, sram_read(addr));
} }
} }
@@ -69,7 +75,7 @@ void test_bulk_read_write()
addr = 0x000000; addr = 0x000000;
sram_bulk_read_start(addr); sram_bulk_read_start(addr);
while (addr <= 0x8000) { while (addr <= 0x8000) {
info_P(PSTR("addr=0x%08lx %x\n"), addr, sram_bulk_read()); info("addr=0x%08lx %x\n", addr, sram_bulk_read());
sram_bulk_read_next(); sram_bulk_read_next();
addr++; addr++;
} }
@@ -85,7 +91,7 @@ void test_non_zero_memory(uint32_t bottom_addr, uint32_t top_addr)
for (addr = bottom_addr; addr < top_addr; addr++) { for (addr = bottom_addr; addr < top_addr; addr++) {
c = sram_bulk_read(); c = sram_bulk_read();
if (c != 0xff) if (c != 0xff)
info_P(PSTR("addr=0x%08lx c=0x%x\n"), addr, c); info("addr=0x%08lx c=0x%x\n", addr, c);
sram_bulk_read_next(); sram_bulk_read_next();
} }
sram_bulk_read_end(); sram_bulk_read_end();
@@ -95,12 +101,56 @@ void test_non_zero_memory(uint32_t bottom_addr, uint32_t top_addr)
void test_crc() void test_crc()
{ {
info_P(PSTR("test_crc: clear\n")); info("test_crc: clear\n");
avr_bus_active(); avr_bus_active();
sram_bulk_set(0x000000, 0x10000, 0xff); sram_bulk_set(0x000000, 0x10000, 0xff);
info_P(PSTR("test_crc: crc\n")); info("test_crc: crc\n");
crc_check_bulk_memory(0x000000, 0x10000, 0x8000); crc_check_bulk_memory(0x000000, 0x10000, 0x8000);
info_P(PSTR("test_crc: check\n")); info("test_crc: check\n");
test_non_zero_memory(0x000000, 0x10000); test_non_zero_memory(0x000000, 0x10000);
} }
void test_sdcard(void){
while (mmc_init() !=0){ //ist der Rückgabewert ungleich NULL ist ein Fehler aufgetreten
printf("no sdcard\n");
}
if (fat_initfat()==0){
printf("fatinit ok\n");
} else {
printf("fatinit failed\n");
return;
}
printf("Root dirlist\n");
ffls_smc();
dump_memory(DIR_ENTRY_LOC , DIR_ENTRY_LOC + (64 * 2));
dir_entry_loop();
while(1);
#if (WRITE==1)
char datei[12]="test.txt"; // hier muss platz für 11 zeichen sein (8.3), da fat_str diesen string benutzt !!
fat_str(datei);
ffrm( datei ); // löschen der datei/ordner falls vorhanden
printf("open %s\n",datei);
ffopen( datei );
printf("write %s\n",datei);
ffwrites((char*)"Hallo Datei :)");
ffwrite(0x0D);
ffwrite(0x0A);
printf("close %s\n",datei);
ffclose();
printf("open %s\n",datei);
ffopen( datei );
printf("open %s\n",datei);
unsigned long int seek=file.length; // eine variable setzen und runterzählen bis 0 geht am schnellsten !
do{
printf("%c",ffread()); // liest ein zeichen und gibt es über uart aus !
}while(--seek); // liest solange bytes da sind (von datei länge bis 0)
ffclose(); // schließt datei
#endif
}

View File

@@ -27,5 +27,6 @@ void test_read_write();
void test_bulk_read_write(); void test_bulk_read_write();
void test_non_zero_memory(uint32_t bottom_addr, uint32_t top_addr); void test_non_zero_memory(uint32_t bottom_addr, uint32_t top_addr);
void test_crc(); void test_crc();
void test_sdcard();
#endif #endif

View File

@@ -29,11 +29,7 @@
#include "debug.h" #include "debug.h"
#include "info.h" #include "info.h"
#include "sram.h"
extern uint8_t snes_reset_line;
#ifndef OCR1A #ifndef OCR1A
#define OCR1A OCR1 // 2313 support #define OCR1A OCR1 // 2313 support
#endif #endif
@@ -56,7 +52,6 @@ uint16_t volatile second; // count seconds
ISR (SIG_OUTPUT_COMPARE1A) ISR (SIG_OUTPUT_COMPARE1A)
{ {
#if XTAL % DEBOUNCE // bei rest #if XTAL % DEBOUNCE // bei rest
OCR1A = 20000000UL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times OCR1A = 20000000UL / DEBOUNCE - 1; // compare DEBOUNCE - 1 times

View File

@@ -31,7 +31,10 @@ volatile struct {
uint8_t rx_int:1; uint8_t rx_int:1;
} intflags; } intflags;
/*
* * Last character read from the UART.
*
*/
volatile char rxbuff; volatile char rxbuff;

View File

@@ -56,14 +56,14 @@ uint8_t usbFunctionWrite(uint8_t * data, uint8_t len)
uint8_t i; uint8_t i;
if (len > rx_remaining) { if (len > rx_remaining) {
info_P(PSTR("ERROR:usbFunctionWrite more data than expected remain: %i len: %i\n"), info("ERROR:usbFunctionWrite more data than expected remain: %i len: %i\n",
rx_remaining, len); rx_remaining, len);
len = rx_remaining; len = rx_remaining;
} }
if (req_state == REQ_STATUS_BULK_UPLOAD) { if (req_state == REQ_STATUS_BULK_UPLOAD) {
rx_remaining -= len; rx_remaining -= len;
debug_P(DEBUG_USB_TRANS, PSTR("usbFunctionWrite REQ_STATUS_BULK_UPLOAD addr: 0x%08lx len: %i rx_remaining=%i\n"), debug(DEBUG_USB_TRANS,"usbFunctionWrite REQ_STATUS_BULK_UPLOAD addr: 0x%08lx len: %i rx_remaining=%i\n",
req_addr, len, rx_remaining); req_addr, len, rx_remaining);
ptr = data; ptr = data;
i = len; i = len;
@@ -72,6 +72,8 @@ uint8_t usbFunctionWrite(uint8_t * data, uint8_t len)
sram_bulk_write_next(); sram_bulk_write_next();
} }
} }
/* test this */
//return rx_remaining == 0
return len; return len;
} }
@@ -81,7 +83,7 @@ uint8_t usbFunctionRead(uint8_t * data, uint8_t len)
if (len > tx_remaining) if (len > tx_remaining)
len = tx_remaining; len = tx_remaining;
tx_remaining -= len; tx_remaining -= len;
debug_P(DEBUG_USB_TRANS, PSTR("usbFunctionRead len=%i tx_remaining=%i \n"), len, tx_remaining); debug(DEBUG_USB_TRANS,"usbFunctionRead len=%i tx_remaining=%i \n", len, tx_remaining);
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
*data = tx_buffer[len]; *data = tx_buffer[len];

View File

@@ -248,8 +248,8 @@ section at the end of this file).
* obdev's free shared VID/PID pair. See the file USBID-License.txt for * obdev's free shared VID/PID pair. See the file USBID-License.txt for
* details. * details.
*/ */
#define USB_CFG_DEVICE_NAME 'Q', 'U', 'I', 'C', 'K', 'D', 'E', 'V', '1', '6' #define USB_CFG_DEVICE_NAME 'S', 'N', 'E', 'S', 'R', 'A', 'M'
#define USB_CFG_DEVICE_NAME_LEN 10 #define USB_CFG_DEVICE_NAME_LEN 7
/* Same as above for the device name. If you don't want a device name, undefine /* Same as above for the device name. If you don't want a device name, undefine
* the macros. See the file USBID-License.txt before you assign a name if you * the macros. See the file USBID-License.txt before you assign a name if you
* use a shared VID/PID. * use a shared VID/PID.

View File

View File

@@ -3,7 +3,7 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>currentDocument</key> <key>currentDocument</key>
<string>avr/usbload/irq.c</string> <string>avr/usbload/dir.c</string>
<key>documents</key> <key>documents</key>
<array> <array>
<dict> <dict>
@@ -21,79 +21,19 @@
<integer>271</integer> <integer>271</integer>
<key>metaData</key> <key>metaData</key>
<dict> <dict>
<key>README</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>49</integer>
<key>line</key>
<integer>7</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>1</integer>
<key>line</key>
<integer>7</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>49</integer>
<key>line</key>
<integer>7</integer>
</dict>
</dict>
<key>avr/bootloader/bootloader.c</key> <key>avr/bootloader/bootloader.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>6</integer>
<key>line</key> <key>line</key>
<integer>31</integer> <integer>268</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>30</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>31</integer>
</dict>
</dict>
<key>avr/bootloader/bootloader.hex</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>381</integer>
</dict> </dict>
<key>avr/bootloader/config.h</key> <key>avr/bootloader/config.h</key>
<dict> <dict>
@@ -109,92 +49,6 @@
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>0</integer>
</dict> </dict>
<key>avr/bootloader/interrupts.S</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/bootloader/usbconfig.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>39</integer>
<key>line</key>
<integer>50</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>144</integer>
</dict>
<key>avr/usbload/checksize</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>12</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/command.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>22</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>14</integer>
</dict>
<key>avr/usbload/command.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>16</integer>
<key>line</key>
<integer>25</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>29</integer>
</dict>
</dict>
<key>avr/usbload/config.h</key> <key>avr/usbload/config.h</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
@@ -202,7 +56,7 @@
<key>column</key> <key>column</key>
<integer>38</integer> <integer>38</integer>
<key>line</key> <key>line</key>
<integer>46</integer> <integer>28</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
@@ -214,51 +68,23 @@
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>20</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>81</integer> <integer>0</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>41</integer> <integer>53</integer>
</dict> </dict>
<key>avr/usbload/crc.h</key> <key>avr/usbload/crc.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>26</integer>
<key>line</key>
<integer>6</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/debug.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>31</integer>
<key>line</key>
<integer>39</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/debug.h</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>33</integer> <integer>26</integer>
</dict> </dict>
<key>columnSelection</key> <key>columnSelection</key>
<false/> <false/>
@@ -271,14 +97,58 @@
<key>column</key> <key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>31</integer> <integer>25</integer>
</dict> </dict>
<key>selectTo</key> <key>selectTo</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>33</integer> <integer>26</integer>
</dict>
</dict>
<key>avr/usbload/dir.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>27</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>45</integer>
</dict>
<key>avr/usbload/dir.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>3</integer>
<key>line</key>
<integer>48</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>13</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>48</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>6</integer>
<key>line</key>
<integer>48</integer>
</dict> </dict>
</dict> </dict>
<key>avr/usbload/dump.c</key> <key>avr/usbload/dump.c</key>
@@ -286,30 +156,14 @@
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>13</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>67</integer> <integer>26</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>31</integer> <integer>1</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>5</integer>
<key>line</key>
<integer>67</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>16</integer>
<key>line</key>
<integer>67</integer>
</dict>
</dict> </dict>
<key>avr/usbload/dump.h</key> <key>avr/usbload/dump.h</key>
<dict> <dict>
@@ -325,19 +179,65 @@
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>0</integer>
</dict> </dict>
<key>avr/usbload/fifo.c</key> <key>avr/usbload/fat.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>17</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>22</integer> <integer>13</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>0</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>12</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>13</integer>
</dict>
</dict>
<key>avr/usbload/fat.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>15</integer>
<key>line</key>
<integer>71</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>13</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>13</integer>
<key>line</key>
<integer>71</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>25</integer>
<key>line</key>
<integer>71</integer>
</dict>
</dict> </dict>
<key>avr/usbload/fifo.h</key> <key>avr/usbload/fifo.h</key>
<dict> <dict>
@@ -353,84 +253,44 @@
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>0</integer>
</dict> </dict>
<key>avr/usbload/info.c</key> <key>avr/usbload/file.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>4</integer> <integer>20</integer>
<key>line</key> <key>line</key>
<integer>33</integer> <integer>33</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>1</integer>
</dict> <key>selectFrom</key>
<key>avr/usbload/info.h</key>
<dict>
<key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>22</integer> <integer>16</integer>
<key>line</key> <key>line</key>
<integer>32</integer> <integer>33</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>selectTo</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/irq.c</key>
<dict>
<key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>20</integer>
<key>line</key> <key>line</key>
<integer>28</integer> <integer>33</integer>
</dict> </dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>11</integer>
</dict> </dict>
<key>avr/usbload/irq.h</key> <key>avr/usbload/file.h</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>13</integer> <integer>20</integer>
<key>line</key> <key>line</key>
<integer>22</integer> <integer>20</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/loader.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>443</integer>
</dict>
<key>avr/usbload/loader.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>9</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
@@ -444,37 +304,35 @@
<key>column</key> <key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>30</integer> <integer>320</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>313</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>29</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>30</integer>
</dict>
</dict> </dict>
<key>avr/usbload/rle.h</key> <key>avr/usbload/mmc.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>220</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>169</integer>
</dict>
<key>avr/usbload/mmc.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer> <integer>0</integer>
<key>line</key>
<integer>39</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
@@ -486,70 +344,118 @@
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>41</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>135</integer> <integer>0</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>108</integer> <integer>111</integer>
</dict> </dict>
<key>avr/usbload/shared_memory.h</key> <key>avr/usbload/shared_memory.h</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>50</integer> <integer>48</integer>
<key>line</key> <key>line</key>
<integer>50</integer> <integer>51</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>22</integer> <integer>14</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>44</integer>
<key>line</key>
<integer>51</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>52</integer>
<key>line</key>
<integer>51</integer>
</dict>
</dict> </dict>
<key>avr/usbload/sram.c</key> <key>avr/usbload/sram.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>24</integer> <integer>0</integer>
<key>line</key> <key>line</key>
<integer>34</integer> <integer>299</integer>
</dict> </dict>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>273</integer>
</dict> </dict>
<key>avr/usbload/sram.h</key> <key>avr/usbload/sram.h</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>3</integer>
<key>line</key> <key>line</key>
<integer>183</integer> <integer>200</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>118</integer> <integer>158</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>71</integer>
<key>line</key>
<integer>200</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>3</integer>
<key>line</key>
<integer>200</integer>
</dict>
</dict> </dict>
<key>avr/usbload/testing.c</key> <key>avr/usbload/testing.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
<dict> <dict>
<key>column</key> <key>column</key>
<integer>0</integer> <integer>31</integer>
<key>line</key> <key>line</key>
<integer>106</integer> <integer>147</integer>
</dict> </dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key> <key>firstVisibleColumn</key>
<integer>0</integer> <integer>0</integer>
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>25</integer> <integer>105</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>27</integer>
<key>line</key>
<integer>147</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>31</integer>
<key>line</key>
<integer>147</integer>
</dict>
</dict> </dict>
<key>avr/usbload/testing.h</key> <key>avr/usbload/testing.h</key>
<dict> <dict>
@@ -565,136 +471,6 @@
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>0</integer> <integer>0</integer>
</dict> </dict>
<key>avr/usbload/timer.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>41</integer>
<key>line</key>
<integer>61</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>28</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>94</integer>
</dict>
</dict>
<key>avr/usbload/timer.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>29</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/uart.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>34</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>44</integer>
</dict>
<key>avr/usbload/usb_bulk.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>74</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>40</integer>
</dict>
<key>avr/usbload/usbconfig.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>80</integer>
<key>line</key>
<integer>251</integer>
</dict>
<key>columnSelection</key>
<false/>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>231</integer>
<key>selectFrom</key>
<dict>
<key>column</key>
<integer>32</integer>
<key>line</key>
<integer>251</integer>
</dict>
<key>selectTo</key>
<dict>
<key>column</key>
<integer>80</integer>
<key>line</key>
<integer>251</integer>
</dict>
</dict>
<key>avr/usbload/watchdog.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>22</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>avr/usbload/watchdog.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>poc/avr_sdcard/fat.c</key> <key>poc/avr_sdcard/fat.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
@@ -825,48 +601,6 @@
<key>firstVisibleLine</key> <key>firstVisibleLine</key>
<integer>211</integer> <integer>211</integer>
</dict> </dict>
<key>tools/ucon64/2.0/src/backup/f2a.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>558</integer>
</dict>
<key>tools/ucon64/2.0/src/backup/fal.c</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>0</integer>
<key>line</key>
<integer>0</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>0</integer>
</dict>
<key>tools/ucon64/2.0/src/backup/snesram.h</key>
<dict>
<key>caret</key>
<dict>
<key>column</key>
<integer>38</integer>
<key>line</key>
<integer>70</integer>
</dict>
<key>firstVisibleColumn</key>
<integer>0</integer>
<key>firstVisibleLine</key>
<integer>30</integer>
</dict>
<key>tools/ucon64/2.0/src/console/snes.c</key> <key>tools/ucon64/2.0/src/console/snes.c</key>
<dict> <dict>
<key>caret</key> <key>caret</key>
@@ -886,51 +620,31 @@
<array> <array>
<string>avr/usbload/testing.h</string> <string>avr/usbload/testing.h</string>
<string>avr/usbload/testing.c</string> <string>avr/usbload/testing.c</string>
<string>avr/usbload/timer.c</string> <string>avr/usbload/mmc.c</string>
<string>avr/usbload/irq.c</string>
<string>avr/bootloader/bootloader.hex</string>
<string>avr/usbload/irq.h</string>
<string>avr/usbload/timer.h</string>
<string>avr/usbload/uart.c</string>
<string>avr/usbload/usb_bulk.c</string>
<string>avr/usbload/watchdog.c</string>
<string>avr/usbload/watchdog.h</string>
<string>poc/avr_sdcard/fat.c</string> <string>poc/avr_sdcard/fat.c</string>
<string>poc/avr_sdcard/fat.h</string> <string>poc/avr_sdcard/fat.h</string>
<string>poc/avr_sdcard/main.lst</string> <string>poc/avr_sdcard/main.lst</string>
<string>avr/bootloader/config.h</string> <string>avr/bootloader/config.h</string>
<string>avr/bootloader/bootloader.c</string> <string>avr/bootloader/bootloader.c</string>
<string>README</string> <string>avr/usbload/dir.h</string>
<string>avr/bootloader/usbconfig.h</string>
<string>avr/usbload/debug.c</string>
<string>avr/usbload/dump.h</string> <string>avr/usbload/dump.h</string>
<string>avr/usbload/file.c</string>
<string>avr/usbload/fat.h</string>
<string>avr/usbload/file.h</string>
<string>avr/usbload/crc.c</string> <string>avr/usbload/crc.c</string>
<string>avr/usbload/command.h</string> <string>avr/usbload/fat.c</string>
<string>avr/usbload/dir.c</string>
<string>avr/usbload/dump.c</string> <string>avr/usbload/dump.c</string>
<string>avr/usbload/loader.h</string>
<string>avr/usbload/info.h</string>
<string>avr/usbload/loader.c</string>
<string>avr/usbload/fifo.c</string>
<string>avr/usbload/command.c</string>
<string>avr/usbload/debug.h</string>
<string>avr/usbload/rle.h</string>
<string>avr/usbload/config.h</string> <string>avr/usbload/config.h</string>
<string>tools/ucon64/2.0/src/console/snes.c</string> <string>tools/ucon64/2.0/src/console/snes.c</string>
<string>poc/avr_sdcard/main.c</string> <string>poc/avr_sdcard/main.c</string>
<string>poc/avr_usbload/sram.c</string> <string>poc/avr_usbload/sram.c</string>
<string>avr/usbload/sram.h</string> <string>avr/usbload/sram.h</string>
<string>tools/ucon64/2.0/src/backup/snesram.h</string>
<string>avr/usbload/shared_memory.h</string> <string>avr/usbload/shared_memory.h</string>
<string>avr/usbload/checksize</string>
<string>avr/usbload/shared_memory.c</string> <string>avr/usbload/shared_memory.c</string>
<string>avr/bootloader/interrupts.S</string>
<string>avr/usbload/info.c</string>
<string>avr/usbload/fifo.h</string> <string>avr/usbload/fifo.h</string>
<string>avr/usbload/main.c</string> <string>avr/usbload/main.c</string>
<string>avr/usbload/sram.c</string> <string>avr/usbload/sram.c</string>
<string>tools/ucon64/2.0/src/backup/fal.c</string>
<string>tools/ucon64/2.0/src/backup/f2a.c</string>
<string>avr/usbload/usbconfig.h</string>
<string>avr/usbload/crc.h</string> <string>avr/usbload/crc.h</string>
</array> </array>
<key>showFileHierarchyDrawer</key> <key>showFileHierarchyDrawer</key>
@@ -967,6 +681,45 @@
</dict> </dict>
</dict> </dict>
</dict> </dict>
<key>tools</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict>
<key>ucon64</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict>
<key>2.0</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict>
<key>src</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict>
<key>console</key>
<dict>
<key>isExpanded</key>
<true/>
<key>subItems</key>
<dict/>
</dict>
</dict>
</dict>
</dict>
</dict>
</dict>
</dict>
</dict>
</dict>
</dict> </dict>
</dict> </dict>
</dict> </dict>

View File

View File

@@ -1,77 +0,0 @@
# SDK Config
PLATFORM=$(shell uname)
ifeq ($(PLATFORM),Linux)
# Linux Wine
SDK=/home/david/.wine/drive_c/65xx_FreeSDK
WINE=wine
EMU=../../tools/bsnes/bsnes
DISASM=/home/david/Devel/arch/snes/devkit/bin/disasm
UCON=ucon64
else
# Mac Wine
SDK=/Users/david/.wine/drive_c/65xx_FreeSDK
WINE=wine
EMU=zsnes
DISASM=/Users/david/Devel/arch/snes/devkit/bin/disasm
UCON=ucon64
endif
CC=$(WINE) $(SDK)/bin/WDC816CC.exe
AS=$(WINE) $(SDK)/bin/WDC816AS.exe
LD=$(WINE) $(SDK)/bin/WDCLN.exe
PADBIN=$(WINE) tools/padbin.exe
# Project
INC=$(SDK)/include
LIBS=-L$(SDK)/lib/cc
#-L$(SDK)/lib/c134
OBJS=StartupSnes.obj main.obj pad.obj PPU.obj debug.obj ressource.obj
APP=loadertest.smc
GFX=debugfont
all: $(APP)
run:
$(EMU) $(APP)
disasm: $(APP)
rm -rf $(APP)
$(DISASM) $(APP) > $(APP).asm
upload: header
ucon64 --port=usb --xsnesram $(APP)
repair: $(APP)
$(UCON) -snes -chk $(APP) 2>&1 >/dev/null
rm -rf *.bak
header: $(APP)
$(UCON) -smc $(APP)
rm -rf *.bak
StartupSnes.obj: StartupSnes.asm
$(AS) -V $?
ressource.obj: ressource.asm
$(AS) -V $?
%.obj: %.c
$(CC) -wl -wp -sop -MC -I $(INC) $?
$(APP): $(OBJS)
$(LD) -B -HB -M21 -V -T -Pff \
-C008000,0000 -U0000,0000 \
-Avectors=FFE4,7FE4 \
-Aregistration_data=FFB0,7FB0 \
-Aressource=18000,8000 \
-N $(OBJS) $(LIBS) -O $@
$(PADBIN) 0x20000 $(APP)
clean:
rm -vf $(APP) *.obj *.TMP

View File

@@ -1,90 +0,0 @@
#include "data.h"
byte tileMapLocation[4];
word characterLocation[4];
void waitForVBlank(void)
{
byte Status;
do {
Status = *(byte *) 0x4210;
} while (!(Status & 0x80));
}
void setTileMapLocation(word vramDst, byte screenProp, byte bgNumber)
{
tileMapLocation[bgNumber] = ((vramDst >> 8) & 0xfc) | (screenProp & 0x03);
*(byte *) (0x2107 + bgNumber) = tileMapLocation[bgNumber];
}
void restoreTileMapLocation(byte bgNumber)
{
*(byte *) (0x2107 + bgNumber) = tileMapLocation[bgNumber];
}
void setCharacterLocation(word vramDst, byte bgNumber)
{
characterLocation[bgNumber] = vramDst;
if (bgNumber < 2) {
*(byte *) 0x210b =
(characterLocation[1] >> 8 & 0xf0) + (characterLocation[0] >> 12);
} else {
*(byte *) 0x210c =
(characterLocation[3] >> 8 & 0xf0) + (characterLocation[2] >> 12);
}
}
void restoreCharacterLocation(byte bgNumber)
{
setCharacterLocation(characterLocation[bgNumber], bgNumber);
}
void VRAMByteWrite(byte value, word vramDst)
{
*(byte *) 0x2115 = 0x80;
*(word *) 0x2116 = vramDst;
*(byte *) 0x2118 = value;
}
void VRAMLoad(word src, word vramDst, word size)
{
// set address in VRam for read or write ($2116) + block size transfer ($2115)
*(byte *) 0x2115 = 0x80;
*(word *) 0x2116 = vramDst;
*(word *) 0x4300 = 0x1801; // set DMA control register (1 word inc)
// and destination ($21xx xx -> 0x18)
*(word *) 0x4302 = src; // DMA channel x source address offset
// (low $4302 and high $4303 optimisation)
*(byte *) 0x4304 = 0x01; // DMA channel x source address bank
*(word *) 0x4305 = size; // DMA channel x transfer size
// (low $4305 and high $4306 optimisation)
// Turn on DMA transfer for this channel
waitForVBlank();
*(byte *) 0x2100 = 0x80;
*(byte *) 0x420b = 0x01;
*(byte *) 0x2100 = 0x00;
}
void CGRAMLoad(word src, byte cgramDst, word size)
{
// set address in VRam for read or write + block size
*(byte *) 0x2121 = cgramDst;
*(word *) 0x4300 = 0x2200; // set DMA control register (1 byte inc)
// and destination ($21xx xx -> 022)
*(word *) 0x4302 = src; // DMA channel x source address offset
// (low $4302 and high $4303 optimisation)
*(byte *) 0x4304 = 0x01; // DMA channel x source address bank
*(word *) 0x4305 = size; // DMA channel x transfer size
// (low $4305 and high $4306 optimisation)
// Turn on DMA transfer for this channel
waitForVBlank();
*(byte *) 0x2100 = 0x80;
*(byte *) 0x420b = 0x01;
*(byte *) 0x2100 = 0x00;
}

View File

@@ -1,11 +0,0 @@
extern byte tileMapLocation[4];
extern word characterLocation[4];
void waitForVBlank(void);
void setTileMapLocation(word vramDst, byte screenProp, byte bgNumber);
void restoreTileMapLocation(byte bgNumber);
void setCharacterLocation(word vramDst, byte bgNumber);
void restoreCharacterLocation(byte bgNumber);
void VRAMByteWrite(byte value, word vramDst);
void VRAMLoad(word src, word vramDst, word size);
void CGRAMLoad(word src, byte cgramDst, word size);

View File

@@ -1,240 +0,0 @@
; SNES ROM startup code
;******************************************************************************
;*** Define a special section in case most of the code is not in bank 0. ***
;******************************************************************************
;STACK EQU $01ff ;CHANGE THIS FOR YOUR SYSTEM
;STARTUP SECTION OFFSET $008000
CODE
XDEF START
START:
XREF _~main
sei ; Disabled interrupts
clc ; clear carry to switch to native mode
xce ; Xchange carry & emulation bit. native mode
rep #$18 ; Binary mode (decimal mode off), X/Y 16 bit
LONGI ON
ldx #$1FFF ; set stack to $1FFF
txs
rep #$30
longa on
longi on
; Init data used for heap
; see heap definition below
XREF _~_heap_top
XREF _~_mem_start
stz _~_heap_top
stz _~_mem_start
XREF _~preInit
jsr >_~preInit
sep #$30 ; X,Y,A are 8 bit numbers
LONGA OFF
LONGI OFF
lda #$8F ; screen off, full brightness
sta $2100 ; brightness + screen enable register
stz $2101 ; Sprite register (size + address in VRAM)
stz $2102 ; Sprite registers (address of sprite memory [OAM])
stz $2103 ; "" ""
stz $2105 ; Mode 0, = Graphic mode register
stz $2106 ; noplanes, no mosaic, = Mosaic register
stz $2107 ; Plane 0 map VRAM location
stz $2108 ; Plane 1 map VRAM location
stz $2109 ; Plane 2 map VRAM location
stz $210A ; Plane 3 map VRAM location
stz $210B ; Plane 0+1 Tile data location
stz $210C ; Plane 2+3 Tile data location
stz $210D ; Plane 0 scroll x (first 8 bits)
stz $210D ; Plane 0 scroll x (last 3 bits) #$0 - #$07ff
stz $210E ; Plane 0 scroll y (first 8 bits)
stz $210E ; Plane 0 scroll y (last 3 bits) #$0 - #$07ff
stz $210F ; Plane 1 scroll x (first 8 bits)
stz $210F ; Plane 1 scroll x (last 3 bits) #$0 - #$07ff
stz $2110 ; Plane 1 scroll y (first 8 bits)
stz $2110 ; Plane 1 scroll y (last 3 bits) #$0 - #$07ff
stz $2111 ; Plane 2 scroll x (first 8 bits)
stz $2111 ; Plane 2 scroll x (last 3 bits) #$0 - #$07ff
stz $2112 ; Plane 2 scroll y (first 8 bits)
stz $2112 ; Plane 2 scroll y (last 3 bits) #$0 - #$07ff
stz $2113 ; Plane 3 scroll x (first 8 bits)
stz $2113 ; Plane 3 scroll x (last 3 bits) #$0 - #$07ff
stz $2114 ; Plane 3 scroll y (first 8 bits)
stz $2114 ; Plane 3 scroll y (last 3 bits) #$0 - #$07ff
lda #$80 ; increase VRAM address after writing to $2119
sta $2115 ; VRAM address increment register
stz $2116 ; VRAM address low
stz $2117 ; VRAM address high
stz $211A ; Initial Mode 7 setting register
stz $211B ; Mode 7 matrix parameter A register (low)
lda #$01
sta $211B ; Mode 7 matrix parameter A register (high)
stz $211C ; Mode 7 matrix parameter B register (low)
stz $211C ; Mode 7 matrix parameter B register (high)
stz $211D ; Mode 7 matrix parameter C register (low)
stz $211D ; Mode 7 matrix parameter C register (high)
stz $211E ; Mode 7 matrix parameter D register (low)
sta $211E ; Mode 7 matrix parameter D register (high)
stz $211F ; Mode 7 center position X register (low)
stz $211F ; Mode 7 center position X register (high)
stz $2120 ; Mode 7 center position Y register (low)
stz $2120 ; Mode 7 center position Y register (high)
stz $2121 ; Color number register ($0-ff)
stz $2123 ; BG1 & BG2 Window mask setting register
stz $2124 ; BG3 & BG4 Window mask setting register
stz $2125 ; OBJ & Color Window mask setting register
stz $2126 ; Window 1 left position register
stz $2127 ; Window 2 left position register
stz $2128 ; Window 3 left position register
stz $2129 ; Window 4 left position register
stz $212A ; BG1, BG2, BG3, BG4 Window Logic register
stz $212B ; OBJ, Color Window Logic Register (or,and,xor,xnor)
sta $212C ; Main Screen designation (planes, sprites enable)
stz $212D ; Sub Screen designation
stz $212E ; Window mask for Main Screen
stz $212F ; Window mask for Sub Screen
lda #$30
sta $2130 ; Color addition & screen addition init setting
stz $2131 ; Add/Sub sub designation for screen, sprite, color
lda #$E0
sta $2132 ; color data for addition/subtraction
stz $2133 ; Screen setting (interlace x,y/enable SFX data)
stz $4200 ; Enable V-blank, interrupt, Joypad register
lda #$FF
sta $4201 ; Programmable I/O port
stz $4202 ; Multiplicand A
stz $4203 ; Multiplier B
stz $4204 ; Multiplier C
stz $4205 ; Multiplicand C
stz $4206 ; Divisor B
stz $4207 ; Horizontal Count Timer
stz $4208 ; Horizontal Count Timer MSB (most significant bit)
stz $4209 ; Vertical Count Timer
stz $420A ; Vertical Count Timer MSB
stz $420B ; General DMA enable (bits 0-7)
stz $420C ; Horizontal DMA (HDMA) enable (bits 0-7)
stz $420D ; Access cycle designation (slow/fast rom)
cli ; Enable interrupts
rep #$30
longa on
longi on
jsr >_~main
brk
XDEF IRQ
IRQ:
XREF _~IRQHandler
LONGA ON
LONGI ON
rep #$30
pha
phx
phy
jsr _~IRQHandler
ply
plx
pla
rti
XDEF NMI
NMI:
XREF _~NMIHandler
LONGA ON
LONGI ON
rep #$30
pha
phx
phy
phd
phb
lda #$0000
sep #$30 ; X,Y,A are 8 bit numbers
LONGA OFF
LONGI OFF
lda $4210 ; Read NMI
LONGA ON
LONGI ON
rep #$30
jsr _~NMIHandler
plb
pld
ply
plx
pla
rti
DIRQ:
rti
ENDS
;******************************************************************************
;*** Heap definition ***
;******************************************************************************
DATA
XDEF _~heap_start
XDEF _~heap_end
_~heap_start:
WORD $1000
_~heap_end:
WORD $1200
;******************************************************************************
;*** SNES ROM Registartion Data ***
;******************************************************************************
REGISTRATION_DATA SECTION
MAKER_CODE FCC /FF/
GAME_CODE FCC /SMWJ/
FIXED_VALUE0 BYTE $00, $00, $00, $00, $00, $00, $00
EXPANSION_RAM_SIZE BYTE $00
SPECIAL_VERSION BYTE $00
CARTRIDGE_TYPE_SUB BYTE $00
GAME_TITLE FCC /GAME TITLE !/
;012345678901234567890;
MAP_MODE BYTE $20
CARTRIDGE_SIZE BYTE $00
ROM_SIZE BYTE $09
RAM_SIZE BYTE $00
DESTINATION_CODE BYTE $00
FIXED_VALUE1 BYTE $33
MASK_ROM_VERSION BYTE $00
COMPLEMENT_CHECK BYTE $00, $00
CHEKSUM BYTE $00, $00
;******************************************************************************
;*** SNES Interrupts and Reset vector ***
;******************************************************************************
VECTORS SECTION
; Native vector
N_COP DW DIRQ
N_BRK DW DIRQ
N_ABORT DW DIRQ
N_NMI DW NMI
N_RSRVD DW DIRQ
N_IRQ DW IRQ
DS 4
; Emulation vector
E_COP DW DIRQ
E_RSRVD DW DIRQ
E_ABORT DW DIRQ
E_NMI DW DIRQ
E_RESET DW START
E_IRQ DW DIRQ
END

View File

@@ -1,37 +0,0 @@
#include "data.h"
word crc_update(char far * data, word size)
{
word i;
word j;
word crc = 0;
for (j = 0; j < size; j++) {
crc = crc ^ ((word) data[j] << 8);
for (i = 0; i < 8; i++) {
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}
return crc;
}
word crc_update_mem(unsigned long addr, word size)
{
word i;
word j;
word crc = 0;
for (j = 0; j < size; j++) {
crc = crc ^ ((word) * (byte *) (addr + j) << 8);
for (i = 0; i < 8; i++) {
if (crc & 0x8000)
crc = (crc << 1) ^ 0x1021;
else
crc <<= 1;
}
}
return crc;
}

View File

@@ -1,3 +0,0 @@
word crc_update(byte * data, word size);
word crc_update_mem(unsigned long, word size);

View File

@@ -1,8 +0,0 @@
#ifndef _DATA
typedef unsigned char byte;
typedef unsigned short word;
#define _DATA
#endif

View File

@@ -1,224 +0,0 @@
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <fcntl.h>
#include "debug.h"
#include "data.h"
#include "pad.h"
#include "PPU.h"
#include "ressource.h"
#define DEBUG_BUFFER_SIZE 128
word debugMap[0x400];
char debug_buffer[DEBUG_BUFFER_SIZE];
char screen_buffer[DEBUG_BUFFER_SIZE];
void debug_init(void)
{
word i;
for (i = 0; i < 0x400; i++) {
debugMap[i] = 0x00;
}
memset(debug_buffer, 0, DEBUG_BUFFER_SIZE);
memset(screen_buffer, 0,DEBUG_BUFFER_SIZE);
}
void debug_enable(void)
{
VRAMLoad((word) debugFont_pic, 0x5000, 2048);
VRAMLoad((word) debugMap, 0x4000, 0x0800);
setTileMapLocation(0x4000, (byte) 0x00, (byte) 0);
setCharacterLocation(0x5000, (byte) 0);
*(byte *) 0x2100 = 0x0f; // enable background
// Font Color
// hex(24 << 10 | 24 << 5 | 24 ) = '0x6318'
*(byte *) 0x2121 = 0x02;
*(byte *) 0x2122 = 0xff;
*(byte *) 0x2122 = 0x7f;
// Font Border Color
*(byte *) 0x2121 = 0x00;
*(byte *) 0x2122 = 0x00;
*(byte *) 0x2122 = 0x00;
// Background Color
*(byte *) 0x2121 = 0x01;
*(byte *) 0x2122 = 0x05;
*(byte *) 0x2122 = 0x29;
}
void clears(void)
{
word i, y;
for (y = 0; y < 20; y++) {
waitForVBlank();
for (i = 0; i < 32; i++) {
*(byte *) 0x2115 = 0x80;
*(word *) 0x2116 = 0x4000 + i + (y * 0x20);
*(byte *) 0x2118 = 0;
}
}
}
void _print_char(word y, word x, char c)
{
waitForVBlank();
VRAMByteWrite((byte) (c - 32), (word) (0x4000 + x + (y * 0x20)));
}
void _print_screen(word y, char *buffer)
{
char l;
unsigned int x;
x = y * 0x20;
l = strlen(buffer);
waitForVBlank();
while (*buffer) {
if (*buffer == '\n') {
while (x++ < 32) {
*(byte *) 0x2115 = 0x80;
*(word *) 0x2116 = 0x4000 + x + (y * 0x20);
*(byte *) 0x2118 = 0;
}
x = 0;
y += 0x20;
buffer++;
waitForVBlank();
continue;
}
*(byte *) 0x2115 = 0x80;
*(word *) 0x2116 = 0x4000 + x;
*(byte *) 0x2118 = *buffer - 32;
x++;
buffer++;
#if 1
waitForVBlank();
#endif
}
}
void _print_console(const char *buffer)
{
while (*buffer)
*(byte *) 0x3000 = *buffer++;
}
void printfc(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsprintf(debug_buffer, fmt, ap);
va_end(ap);
_print_console(debug_buffer);
//memset(debug_buffer,0,DEBUG_BUFFER_SIZE);
}
void printfs(word y, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsprintf(screen_buffer, fmt, ap);
va_end(ap);
_print_screen(y, screen_buffer);
//memset(screen_buffer, 0, DEBUG_BUFFER_SIZE);
}
void printc_packet(unsigned long addr, unsigned int len, byte * packet)
{
unsigned int i, j;
unsigned int sum = 0;
unsigned int last_sum = 0;
unsigned int clear = 0;
for (i = 0; i < len; i += 16) {
sum = 0;
for (j = 0; j < 16; j++) {
sum += packet[i + j];
}
if (!sum) {
clear = 1;
continue;
}
if (last_sum == sum) {
clear = 1;
continue;
}
if (clear) {
printfc("*\n");
clear = 0;
}
printfc("%06lX:", addr + i);
for (j = 0; j < 16; j++) {
printfc(" %02x", packet[i + j]);
}
printfc(" |");
for (j = 0; j < 16; j++) {
if (packet[i + j] >= 33 && packet[i + j] <= 126)
printfc("%c", packet[i + j]);
else
printfc(".");
}
printfc("|\n");
last_sum = sum;
}
}
/*
* keep the linker happy
*/
int open(const char *_name, int _mode)
{
_print_console("open called\n");
return -1;
}
int close(int fd)
{
_print_console("close called\n");
return -1;
}
size_t read(int fd, void *buff, size_t len)
{
_print_console("read called\n");
return 0;
}
size_t write(int fd, void *buffer, size_t len)
{
_print_console("write called\n");
return 0;
}
long lseek(int fd, long off, int count)
{
_print_console("lseek called\n");
return 0;
}
int unlink(const char *name)
{
_print_console("unlink called\n");
return -1;
}
int isatty()
{
_print_console("isatty called\n");
return 1;
}

View File

@@ -1,8 +0,0 @@
#include "data.h"
void debug_init(void);
void debug_enable(void);
void printfs(word y, const char *fmt, ...);
void printfc(const char *fmt, ...);
void clears(void);
void printc_packet(unsigned long addr, unsigned int len, byte * packet);

View File

@@ -1,106 +0,0 @@
#include <stdlib.h>
#include "data.h";
#include "event.h";
event *events;
void initEvents(void)
{
events = NULL;
}
event *createEvent(char (*callback) (word counter))
{
event *myEvent;
myEvent = (event *) malloc(sizeof(event));
myEvent->VBlankCount = 0;
myEvent->callback = callback;
myEvent->nextEvent = NULL;
myEvent->previousEvent = NULL;
return myEvent;
}
event *addEvent(char (*callback) (word counter), int noDuplicateCallback)
{
event *lastEvent;
event *myEvent;
if (events == NULL) {
events = createEvent(callback);
return events;
} else {
lastEvent = events;
// TODO optimise this with noduplicate
while (lastEvent->nextEvent != NULL) {
if (noDuplicateCallback == 1 && lastEvent->callback == *callback) {
return NULL;
}
lastEvent = lastEvent->nextEvent;
}
if (noDuplicateCallback == 1 && lastEvent->callback == *callback) {
return NULL;
}
myEvent = createEvent(callback);
myEvent->previousEvent = lastEvent;
lastEvent->nextEvent = myEvent;
return myEvent;
}
}
void removeEvent(event * eventElement)
{
byte alone = 0;
event *next, *previous;
next = eventElement->nextEvent;
previous = eventElement->previousEvent;
if (eventElement->nextEvent != NULL && eventElement->previousEvent != NULL) {
alone++;
next->previousEvent = previous;
previous->nextEvent = next;
} else if (eventElement->nextEvent != NULL) {
alone++;
next->previousEvent = NULL;
events = next;
} else if (eventElement->previousEvent != NULL) {
alone++;
previous->nextEvent = NULL;
}
free(eventElement);
if (alone == 0) {
events = NULL;
}
}
void processEvents(void)
{
event *currentEvent;
char returnValue;
currentEvent = events;
while (currentEvent != NULL) {
returnValue = currentEvent->callback(currentEvent->VBlankCount);
if (returnValue == EVENT_CONTINUE) {
currentEvent->VBlankCount++;
} else {
removeEvent(currentEvent);
}
currentEvent = currentEvent->nextEvent;
}
}

View File

@@ -1,17 +0,0 @@
typedef struct event {
word VBlankCount;
char (*callback) (word counter);
struct event *previousEvent;
struct event *nextEvent;
} event;
#define EVENT_STOP 0
#define EVENT_CONTINUE 1
extern event *events;
void initEvents(void);
extern event *addEvent(char (*callback) (word counter),
int noDuplicateCallback);
extern void removeEvent(event * eventElement);
extern void processEvents(void);

View File

@@ -1,48 +0,0 @@
/*-------------------------------------------*/
/*
* Integer type definitions for FatFs module
*/
/*-------------------------------------------*/
#ifndef _INTEGER
/*
* These types must be 16-bit, 32-bit or larger integer
*/
typedef int INT;
typedef unsigned int UINT;
/*
* These types must be 8-bit integer
*/
typedef signed char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/*
* These types must be 16-bit integer
*/
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/*
* These types must be 32-bit integer
*/
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
/*
* Boolean type
*/
// enum { false = 0 , true } bool;
//typedef int BOOL;
#define FALSE 0
#define TRUE 1
#define _INTEGER
#endif

View File

@@ -1,93 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "data.h";
#include "pad.h";
#include "event.h";
#include "myEvents.h";
#include "ressource.h";
#include "PPU.h"
#include "debug.h"
#include "integer.h"
typedef void (*FUNC) (void);
padStatus pad1;
void initInternalRegisters(void)
{
characterLocation[0] = 0x0000;
characterLocation[1] = 0x0000;
characterLocation[2] = 0x0000;
characterLocation[3] = 0x0000;
debug_init();
}
void preInit(void)
{
// For testing purpose ...
// Insert code here to be executed before register init
}
void halt(void)
{
while (1);
}
void wait(void)
{
printfc("SNES::wait: press A to continue\n");
enablePad();
pad1 = readPad((byte) 0);
while (!pad1.A) {
waitForVBlank();
pad1 = readPad((byte) 0);
}
printfc("SNES::wait: done\n");
}
void boot(DWORD addr)
{
FUNC fn;
//printfc("SNES::boot addr=%lx\n", addr);
fn = (FUNC) addr;
fn();
}
unsigned char i;
unsigned char j;
void main(void)
{
initInternalRegisters();
*(byte *) 0x2105 = 0x01; // MODE 1 value
*(byte *) 0x212c = 0x01; // Plane 0 (bit one) enable register
*(byte *) 0x212d = 0x00; // All subPlane disable
*(byte *) 0x2100 = 0x0f; // enable background
debug_enable();
i=0;
j=0;
while (1) {
printfs(0,"IRQ COUNT %i", i);
printfs(1,"NMI COUNT %i", j++);
waitForVBlank();
}
}
void IRQHandler(void)
{
i = i + 1;
}
void NMIHandler(void)
{
// processEvents();
}

View File

@@ -1,103 +0,0 @@
#include "data.h";
#include "pad.h";
#include "event.h";
extern padStatus pad1;
extern word scrollValue;
char fadeOut(word counter)
{
static byte fadeOutValue;
if (counter == 0) {
// init fade value
fadeOutValue = 0x0f;
} else {
fadeOutValue--;
}
*(byte *) 0x2100 = fadeOutValue;
if (fadeOutValue == 0x00) {
return EVENT_STOP;
} else {
return EVENT_CONTINUE;
}
}
char fadeIn(word counter)
{
static byte fadeInValue;
if (counter == 0) {
// init fade value
fadeInValue = 0x00;
} else {
fadeInValue++;
}
*(byte *) 0x2100 = fadeInValue;
if (fadeInValue >= 0x0f) {
return EVENT_STOP;
} else {
return EVENT_CONTINUE;
}
}
char mosaicOut(word counter)
{
static byte mosaicOutValue;
if (counter == 0) {
// init fade value
mosaicOutValue = 0xff;
} else {
mosaicOutValue -= 0x10;
}
*(byte *) 0x2106 = mosaicOutValue;
if (mosaicOutValue == 0x0f) {
return EVENT_STOP;
} else {
return EVENT_CONTINUE;
}
}
char mosaicIn(word counter)
{
static byte mosaicInValue;
if (counter == 0) {
// init fade value
mosaicInValue = 0x0f;
} else {
mosaicInValue += 0x10;
}
*(byte *) 0x2106 = mosaicInValue;
if (mosaicInValue == 0xff) {
return EVENT_STOP;
} else {
return EVENT_CONTINUE;
}
}
char NMIReadPad(word counter)
{
pad1 = readPad((byte) 0);
return EVENT_CONTINUE;
}
char scrollLeft(word counter)
{
scrollValue++;
*(byte *) 0x210d = (byte) scrollValue;
*(byte *) 0x210d = (byte) (scrollValue >> 8);
return EVENT_CONTINUE;
}

View File

@@ -1,6 +0,0 @@
char fadeOut(word counter);
char fadeIn(word counter);
char mosaicOut(word counter);
char mosaicIn(word counter);
char NMIReadPad(word counter);
char scrollLeft(word counter);

View File

@@ -1,26 +0,0 @@
#include "data.h";
#include "pad.h";
#include "debug.h";
void enablePad(void)
{
// Enable pad reading and NMI
*(byte *) 0x4200 = 0x01;
}
void disablePad(void)
{
// Enable pad reading and NMI
*(byte *) 0x4200 = 0x00;
}
padStatus readPad(byte padNumber)
{
word test;
padStatus *status;
padNumber = padNumber << 1;
test = (word) * (byte *) 0x4218 + padNumber << 8;
test |= (word) * (byte *) 0x4219 + padNumber;
status = (padStatus *) & test;
return *status;
}

View File

@@ -1,20 +0,0 @@
typedef struct padStatus {
byte right:1;
byte left:1;
byte down:1;
byte up:1;
byte start:1; // Enter
byte select:1; // Space
byte Y:1; // X
byte B:1; // C
// --------------------------------
byte Dummy:4;
byte R:1; // Z
byte L:1; // A
byte X:1; // S
byte A:1; // D
} padStatus;
extern void enablePad(void);
extern void disablePad(void);
extern padStatus readPad(byte padNumber);

View File

@@ -1,9 +0,0 @@
ressource .section
XDEF _~debugFont_pic
_~debugFont_pic
INSERT ressource/debugFont.pic
.ends

View File

@@ -1,2 +0,0 @@
extern word debugFont_pic[];

Binary file not shown.

View File

@@ -1,36 +0,0 @@
import binascii
data = open("rom.smc","r").read()
data = binascii.rlecode_hqx(data)
cfile = open("loader.c","w")
hfile = open("loader.h","w")
hfile.write('''
#ifndef __FIFO_H__
#define __FIFO_H__
#define ROM_SIZE %i
#endif
''' % len(data))
cfile.write('''
#include <avr/pgmspace.h>
#include <loader.h>
const char _rom[ROM_SIZE] PROGMEM = {
''')
for idx,c in enumerate(data):
c = ord(c)
if idx<len(data)-1:
cfile.write("0x%02x," % c)
else:
cfile.write("0x%02x" % c)
if idx and idx%16==0:
cfile.write("\n")
cfile.write('''
};
''')
cfile.close()

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +0,0 @@
#ifndef __FIFO_H__
#define __FIFO_H__
#define ROM_SIZE 30346
#endif

View File

@@ -1,24 +0,0 @@
# 65816 stuff
AC = wla-65816
AFLAGS = -o
LD = wlalink
LDFLAGS = -vsr
FL = snesflash
FLFLAGS = -wf
UCON = ucon64
UCONFLAGS = --port=usb --xsnesram
SFILES = main.asm
OFILES = $(SFILES:.asm=.o)
ROMFILE = main.smc
EMU = zsnes
# spc stuff
SPCAC = wla-spc700
SPCSFILES = data/apu/apucode.asm
SPCOFILES = $(SPCSFILES:.asm=.o)
SPCFILE = $(SPCSFILES:.asm=.bin)
all:
mv -v main.smc main.smc.last
wget http://dforce3000.de/main.smc
python ../../scripts/conv_rle.py main.smc

957
todo.sh
View File

@@ -1,957 +0,0 @@
#! /bin/bash
# NOTE: Todo.sh requires the .todo/config configuration file to run.
# Place the .todo/config file in your home directory or use the -d option for a custom location.
# Your todo/done/report.txt locations
export TODO_DIR=$(pwd)
export TODO_FILE="$TODO_DIR/todo.txt"
export DONE_FILE="$TODO_DIR/done.txt"
export REPORT_FILE="$TODO_DIR/report.txt"
export TMP_FILE="$TODO_DIR/todo.tmp"
[ -f VERSION-FILE ] && . VERSION-FILE || VERSION="@DEV_VERSION@"
version() { sed -e 's/^ //' <<EndVersion
TODO.TXT Command Line Interface v$VERSION
First release: 5/11/2006
Original conception by: Gina Trapani (http://ginatrapani.org)
Contributors: http://github.com/ginatrapani/todo.txt-cli/network
License: GPL, http://www.gnu.org/copyleft/gpl.html
More information and mailing list at http://todotxt.com
Code repository: http://github.com/ginatrapani/todo.txt-cli/tree/master
EndVersion
exit 1
}
# Set script name early.
TODO_SH=$(basename "$0")
export TODO_SH
oneline_usage="$TODO_SH [-fhpantvV] [-d todo_config] action [task_number] [task_description]"
usage()
{
sed -e 's/^ //' <<EndUsage
Usage: $oneline_usage
Try '$TODO_SH -h' for more information.
EndUsage
exit 1
}
shorthelp()
{
sed -e 's/^ //' <<EndHelp
Usage: $oneline_usage
Actions:
add|a "THING I NEED TO DO +project @context"
addto DEST "TEXT TO ADD"
append|app NUMBER "TEXT TO APPEND"
archive
command [ACTIONS]
del|rm NUMBER [TERM]
dp|depri NUMBER
do NUMBER
help
list|ls [TERM...]
listall|lsa [TERM...]
listcon|lsc
listfile|lf SRC [TERM...]
listpri|lsp [PRIORITY]
listproj|lsprj
move|mv NUMBER DEST [SRC]
prepend|prep NUMBER "TEXT TO PREPEND"
pri|p NUMBER PRIORITY
replace NUMBER "UPDATED TODO"
report
See "help" for more details.
EndHelp
exit 0
}
help()
{
sed -e 's/^ //' <<EndHelp
Usage: $oneline_usage
Actions:
add "THING I NEED TO DO +project @context"
a "THING I NEED TO DO +project @context"
Adds THING I NEED TO DO to your todo.txt file on its own line.
Project and context notation optional.
Quotes optional.
addto DEST "TEXT TO ADD"
Adds a line of text to any file located in the todo.txt directory.
For example, addto inbox.txt "decide about vacation"
append NUMBER "TEXT TO APPEND"
app NUMBER "TEXT TO APPEND"
Adds TEXT TO APPEND to the end of the todo on line NUMBER.
Quotes optional.
archive
Moves done items from todo.txt to done.txt and removes blank lines.
command [ACTIONS]
Runs the remaining arguments using only todo.sh builtins.
Will not call any .todo.actions.d scripts.
del NUMBER [TERM]
rm NUMBER [TERM]
Deletes the item on line NUMBER in todo.txt.
If term specified, deletes only the term from the line.
depri NUMBER
dp NUMBER
Deprioritizes (removes the priority) from the item
on line NUMBER in todo.txt.
do NUMBER[, NUMBER, NUMBER, ...]
Marks item(s) on line NUMBER as done in todo.txt.
help
Display this help message.
list [TERM...]
ls [TERM...]
Displays all todo's that contain TERM(s) sorted by priority with line
numbers. If no TERM specified, lists entire todo.txt.
listall [TERM...]
lsa [TERM...]
Displays all the lines in todo.txt AND done.txt that contain TERM(s)
sorted by priority with line numbers. If no TERM specified, lists
entire todo.txt AND done.txt concatenated and sorted.
listcon
lsc
Lists all the task contexts that start with the @ sign in todo.txt.
listfile SRC [TERM...]
lf SRC [TERM...]
Displays all the lines in SRC file located in the todo.txt directory,
sorted by priority with line numbers. If TERM specified, lists
all lines that contain TERM in SRC file.
listpri [PRIORITY]
lsp [PRIORITY]
Displays all items prioritized PRIORITY.
If no PRIORITY specified, lists all prioritized items.
listproj
lsprj
Lists all the projects that start with the + sign in todo.txt.
move NUMBER DEST [SRC]
mv NUMBER DEST [SRC]
Moves a line from source text file (SRC) to destination text file (DEST).
Both source and destination file must be located in the directory defined
in the configuration directory. When SRC is not defined
it's by default todo.txt.
prepend NUMBER "TEXT TO PREPEND"
prep NUMBER "TEXT TO PREPEND"
Adds TEXT TO PREPEND to the beginning of the todo on line NUMBER.
Quotes optional.
pri NUMBER PRIORITY
p NUMBER PRIORITY
Adds PRIORITY to todo on line NUMBER. If the item is already
prioritized, replaces current priority with new PRIORITY.
PRIORITY must be an uppercase letter between A and Z.
replace NUMBER "UPDATED TODO"
Replaces todo on line NUMBER with UPDATED TODO.
report
Adds the number of open todo's and closed done's to report.txt.
Options:
-@
Hide context names in list output. Use twice to show context
names (default).
-+
Hide project names in list output. Use twice to show project
names (default).
-d CONFIG_FILE
Use a configuration file other than the default ~/.todo/config
-f
Forces actions without confirmation or interactive input
-h
Display a short help message
-p
Plain mode turns off colors
-P
Hide priority labels in list output. Use twice to show
priority labels (default).
-a
Don't auto-archive tasks automatically on completion
-n
Don't preserve line numbers; automatically remove blank lines
on task deletion
-t
Prepend the current date to a task automatically
when it's added.
-v
Verbose mode turns on confirmation messages
-vv
Extra verbose mode prints some debugging information
-V
Displays version, license and credits
Environment variables:
TODOTXT_AUTO_ARCHIVE=0 is same as option -a
TODOTXT_CFG_FILE=CONFIG_FILE is same as option -d CONFIG_FILE
TODOTXT_FORCE=1 is same as option -f
TODOTXT_PRESERVE_LINE_NUMBERS=0 is same as option -n
TODOTXT_PLAIN=1 is same as option -p
TODOTXT_DATE_ON_ADD=1 is same as option -t
TODOTXT_VERBOSE=1 is same as option -v
TODOTXT_DEFAULT_ACTION="" run this when called with no arguments
TODOTXT_SORT_COMMAND="sort ..." customize list output
TODOTXT_FINAL_FILTER="sed ..." customize list after color, P@+ hiding
EndHelp
if [ -d "$TODO_ACTIONS_DIR" ]
then
echo ""
for action in "$TODO_ACTIONS_DIR"/*
do
if [ -x "$action" ]
then
"$action" usage
fi
done
echo ""
fi
exit 1
}
die()
{
echo "$*"
exit 1
}
cleanup()
{
[ -f "$TMP_FILE" ] && rm "$TMP_FILE"
exit 0
}
archive()
{
#defragment blank lines
sed -i.bak -e '/./!d' "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && grep "^x " "$TODO_FILE"
grep "^x " "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
cp "$TODO_FILE" "$TMP_FILE"
sed -n 'G; s/\n/&&/; /^\([ ~-]*\n\).*\n\1/d; s/\n//; h; P' "$TMP_FILE" > "$TODO_FILE"
#[[ $TODOTXT_VERBOSE -gt 0 ]] && echo "TODO: Duplicate tasks have been removed."
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $TODO_FILE archived."
cleanup
}
# == PROCESS OPTIONS ==
while getopts ":fhpnatvV+@Pd:" Option
do
case $Option in
'@' )
## HIDE_CONTEXT_NAMES starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_CONTEXT_NAMES++ ))
if [ $(( $HIDE_CONTEXT_NAMES % 2 )) -eq 0 ]
then
## Zero or even value -- show context names
unset HIDE_CONTEXTS_SUBSTITUTION
else
## One or odd value -- hide context names
export HIDE_CONTEXTS_SUBSTITUTION='[[:space:]]@[^[:space:]]\{1,\}'
fi
;;
'+' )
## HIDE_PROJECT_NAMES starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_PROJECT_NAMES++ ))
if [ $(( $HIDE_PROJECT_NAMES % 2 )) -eq 0 ]
then
## Zero or even value -- show project names
unset HIDE_PROJECTS_SUBSTITUTION
else
## One or odd value -- hide project names
export HIDE_PROJECTS_SUBSTITUTION='[[:space:]][+][^[:space:]]\{1,\}'
fi
;;
a )
TODOTXT_AUTO_ARCHIVE=0
;;
d )
TODOTXT_CFG_FILE=$OPTARG
;;
f )
TODOTXT_FORCE=1
;;
h )
shorthelp
;;
n )
TODOTXT_PRESERVE_LINE_NUMBERS=0
;;
p )
TODOTXT_PLAIN=1
;;
P )
## HIDE_PRIORITY_LABELS starts at zero (false); increment it to one
## (true) the first time this flag is seen. Each time the flag
## is seen after that, increment it again so that an even
## number hides project names and an odd number shows project
## names.
: $(( HIDE_PRIORITY_LABELS++ ))
if [ $(( $HIDE_PRIORITY_LABELS % 2 )) -eq 0 ]
then
## Zero or even value -- show priority labels
unset HIDE_PRIORITY_SUBSTITUTION
else
## One or odd value -- hide priority labels
export HIDE_PRIORITY_SUBSTITUTION="([A-Z])[[:space:]]"
fi
;;
t )
TODOTXT_DATE_ON_ADD=1
;;
v )
: $(( TODOTXT_VERBOSE++ ))
;;
V )
version
;;
esac
done
shift $(($OPTIND - 1))
# defaults if not yet defined
TODOTXT_VERBOSE=${TODOTXT_VERBOSE:-1}
TODOTXT_PLAIN=${TODOTXT_PLAIN:-0}
TODOTXT_CFG_FILE=${TODOTXT_CFG_FILE:-$HOME/.todo/config}
TODOTXT_FORCE=${TODOTXT_FORCE:-0}
TODOTXT_PRESERVE_LINE_NUMBERS=${TODOTXT_PRESERVE_LINE_NUMBERS:-1}
TODOTXT_AUTO_ARCHIVE=${TODOTXT_AUTO_ARCHIVE:-1}
TODOTXT_DATE_ON_ADD=${TODOTXT_DATE_ON_ADD:-0}
TODOTXT_DEFAULT_ACTION=${TODOTXT_DEFAULT_ACTION:-}
TODOTXT_SORT_COMMAND=${TODOTXT_SORT_COMMAND:-env LC_COLLATE=C sort -f -k2}
TODOTXT_FINAL_FILTER=${TODOTXT_FINAL_FILTER:-cat}
# Export all TODOTXT_* variables
export ${!TODOTXT_@}
# Default color map
export NONE=''
export BLACK='\\033[0;30m'
export RED='\\033[0;31m'
export GREEN='\\033[0;32m'
export BROWN='\\033[0;33m'
export BLUE='\\033[0;34m'
export PURPLE='\\033[0;35m'
export CYAN='\\033[0;36m'
export LIGHT_GREY='\\033[0;37m'
export DARK_GREY='\\033[1;30m'
export LIGHT_RED='\\033[1;31m'
export LIGHT_GREEN='\\033[1;32m'
export YELLOW='\\033[1;33m'
export LIGHT_BLUE='\\033[1;34m'
export LIGHT_PURPLE='\\033[1;35m'
export LIGHT_CYAN='\\033[1;36m'
export WHITE='\\033[1;37m'
export DEFAULT='\\033[0m'
# Default priority->color map.
export PRI_A=$YELLOW # color for A priority
export PRI_B=$GREEN # color for B priority
export PRI_C=$LIGHT_BLUE # color for C priority
export PRI_X=$WHITE # color for rest of them
[ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT="$HOME/todo.cfg"
if [ -e "$CFG_FILE_ALT" ]
then
TODOTXT_CFG_FILE="$CFG_FILE_ALT"
fi
}
[ -e "$TODOTXT_CFG_FILE" ] || {
CFG_FILE_ALT="$HOME/.todo.cfg"
if [ -e "$CFG_FILE_ALT" ]
then
TODOTXT_CFG_FILE="$CFG_FILE_ALT"
fi
}
if [ -z "$TODO_ACTIONS_DIR" -o ! -d "$TODO_ACTIONS_DIR" ]
then
TODO_ACTIONS_DIR="$HOME/.todo/actions"
export TODO_ACTIONS_DIR
fi
[ -d "$TODO_ACTIONS_DIR" ] || {
TODO_ACTIONS_DIR_ALT="$HOME/.todo.actions.d"
if [ -d "$TODO_ACTIONS_DIR_ALT" ]
then
TODO_ACTIONS_DIR="$TODO_ACTIONS_DIR_ALT"
fi
}
# === SANITY CHECKS (thanks Karl!) ===
#[ -r "$TODOTXT_CFG_FILE" ] || die "Fatal error: Cannot read configuration file $TODOTXT_CFG_FILE"
#. "$TODOTXT_CFG_FILE"
ACTION=${1:-$TODOTXT_DEFAULT_ACTION}
[ -z "$ACTION" ] && usage
[ -d "$TODO_DIR" ] || die "Fatal Error: $TODO_DIR is not a directory"
( cd "$TODO_DIR" ) || die "Fatal Error: Unable to cd to $TODO_DIR"
[ -w "$TMP_FILE" ] || echo -n > "$TMP_FILE" || die "Fatal Error: Unable to write to $TMP_FILE"
[ -f "$TODO_FILE" ] || cp /dev/null "$TODO_FILE"
[ -f "$DONE_FILE" ] || cp /dev/null "$DONE_FILE"
[ -f "$REPORT_FILE" ] || cp /dev/null "$REPORT_FILE"
if [ $TODOTXT_PLAIN = 1 ]; then
PRI_A=$NONE
PRI_B=$NONE
PRI_C=$NONE
PRI_X=$NONE
DEFAULT=$NONE
fi
# === HEAVY LIFTING ===
shopt -s extglob
_list() {
local FILE="$1"
## If the file starts with a "/" use absolute path. Otherwise,
## try to find it in either $TODO_DIR or using a relative path
if [ "${1:0:1}" == / ]
then
## Absolute path
src="$FILE"
elif [ -f "$TODO_DIR/$FILE" ]
then
## Path relative to todo.sh directory
src="$TODO_DIR/$1"
elif [ -f "$FILE" ]
then
## Path relative to current working directory
src="$FILE"
else
echo "TODO: File $FILE does not exist."
exit 1
fi
## Get our search arguments, if any
shift ## was file name, new $1 is first search term
## Prefix the filter_command with the pre_filter_command
filter_command="${pre_filter_command:-}"
for search_term in "$@"
do
## See if the first character of $search_term is a dash
if [ ${search_term:0:1} != '-' ]
then
## First character isn't a dash: hide lines that don't match
## this $search_term
filter_command="${filter_command:-} ${filter_command:+|} \
grep -i \"$search_term\" "
else
## First character is a dash: hide lines that match this
## $search_term
#
## Remove the first character (-) before adding to our filter command
filter_command="${filter_command:-} ${filter_command:+|} \
grep -v -i \"${search_term:1}\" "
fi
done
## If post_filter_command is set, append it to the filter_command
[ -n "$post_filter_command" ] && {
filter_command="${filter_command:-}${filter_command:+ | }${post_filter_command:-}"
}
## Figure out how much padding we need to use
## We need one level of padding for each power of 10 $LINES uses
LINES=$( sed -n '$ =' "$src" )
PADDING=${#LINES}
## Number the file, then run the filter command,
## then sort and mangle output some more
items=$(
sed = "$src" \
| sed "N; s/^/ /; s/ *\(.\{$PADDING,\}\)\n/\1 /" \
| grep -v "^[0-9]\+ *$"
)
if [ "${filter_command}" ]; then
filtered_items=$(echo -ne "$items" | eval ${filter_command})
else
filtered_items=$items
fi
filtered_items=$(
echo -ne "$filtered_items" \
| sed '''
s/^ /00000/;
s/^ /0000/;
s/^ /000/;
s/^ /00/;
s/^ /0/;
''' \
| eval ${TODOTXT_SORT_COMMAND} \
| sed '''
/^[0-9]\{'$PADDING'\} x /! {
s/\(.*(A).*\)/'$PRI_A'\1'$DEFAULT'/g;
s/\(.*(B).*\)/'$PRI_B'\1'$DEFAULT'/g;
s/\(.*(C).*\)/'$PRI_C'\1'$DEFAULT'/g;
s/\(.*([D-Z]).*\)/'$PRI_X'\1'$DEFAULT'/g;
}
''' \
| sed '''
s/'${HIDE_PRIORITY_SUBSTITUTION:-^}'//g
s/'${HIDE_PROJECTS_SUBSTITUTION:-^}'//g
s/'${HIDE_CONTEXTS_SUBSTITUTION:-^}'//g
''' \
| eval ${TODOTXT_FINAL_FILTER} \
)
echo -ne "$filtered_items${filtered_items:+\n}"
if [ $TODOTXT_VERBOSE -gt 0 ]; then
NUMTASKS=$( echo -ne "$filtered_items" | sed -n '$ =' )
TOTALTASKS=$( echo -ne "$items" | sed -n '$ =' )
echo "--"
echo "TODO: ${NUMTASKS:-0} of ${TOTALTASKS:-0} tasks shown from $FILE"
fi
if [ $TODOTXT_VERBOSE -gt 1 ]
then
echo "TODO DEBUG: Filter Command was: ${filter_command:-cat}"
fi
}
export -f _list
# == HANDLE ACTION ==
action=$( printf "%s\n" "$ACTION" | tr 'A-Z' 'a-z' )
## If the first argument is "command", run the rest of the arguments
## using todo.sh builtins.
## Else, run a actions script with the name of the command if it exists
## or fallback to using a builtin
if [ "$action" == command ]
then
## Get rid of "command" from arguments list
shift
## Reset action to new first argument
action=$( printf "%s\n" "$1" | tr 'A-Z' 'a-z' )
elif [ -d "$TODO_ACTIONS_DIR" -a -x "$TODO_ACTIONS_DIR/$action" ]
then
"$TODO_ACTIONS_DIR/$action" "$@"
cleanup
fi
## Only run if $action isn't found in .todo.actions.d
case $action in
"add" | "a")
if [[ -z "$2" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Add: "
read input
else
[ -z "$2" ] && die "usage: $TODO_SH add \"TODO ITEM\""
shift
input=$*
fi
if [[ $TODOTXT_DATE_ON_ADD = 1 ]]; then
now=`date '+%Y-%m-%d'`
input="$now $input"
fi
echo "$input" >> "$TODO_FILE"
TASKNUM=$(sed -n '$ =' "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added on line $TASKNUM."
cleanup;;
"addto" )
[ -z "$2" ] && die "usage: $TODO_SH addto DEST \"TODO ITEM\""
dest="$TODO_DIR/$2"
[ -z "$3" ] && die "usage: $TODO_SH addto DEST \"TODO ITEM\""
shift
shift
input=$*
if [ -f "$dest" ]; then
echo "$input" >> "$dest"
TASKNUM=$(sed -n '$ =' "$dest")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$input' added to $dest on line $TASKNUM."
else
echo "TODO: Destination file $dest does not exist."
fi
cleanup;;
"append" | "app" )
errmsg="usage: $TODO_SH append ITEM# \"TEXT TO APPEND\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Append: "
read input
else
input=$*
fi
if sed -i.bak $item" s|^.*|& $input|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else
echo "TODO: Error appending task $item."
fi
cleanup;;
"archive" )
archive;;
"del" | "rm" )
# replace deleted line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $TODO_SH del ITEM#"
item=$2
[ -z "$item" ] && die "$errmsg"
if [ -z "$3" ]; then
[[ "$item" = +([0-9]) ]] || die "$errmsg"
if sed -ne "$item p" "$TODO_FILE" | grep "^."; then
DELETEME=$(sed "$item!d" "$TODO_FILE")
if [ $TODOTXT_FORCE = 0 ]; then
echo "Delete '$DELETEME'? (y/n)"
read ANSWER
else
ANSWER="y"
fi
if [ "$ANSWER" = "y" ]; then
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers)
sed -i.bak -e $item"s/^.*//" -e '/./!d' "$TODO_FILE"
else
# leave blank line behind (preserves line numbers)
sed -i.bak -e $item"s/^.*//" "$TODO_FILE"
fi
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$DELETEME' deleted."
cleanup
else
echo "TODO: No tasks were deleted."
fi
else
echo "$item: No such todo."
fi
else
sed -i.bak -e $item"s/$3/ /g" "$TODO_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $3 removed from $item."
fi ;;
"depri" | "dp" )
item=$2
errmsg="usage: $TODO_SH depri ITEM#"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
[[ "$item" = +([0-9]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" "$TODO_FILE" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" "$TODO_FILE"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item deprioritized."
cleanup
else
die "$errmsg"
fi;;
"do" )
errmsg="usage: $TODO_SH do ITEM#"
# shift so we get arguments to the do request
shift;
# Split multiple do's, if comma seperated change to whitespace sepereated
# Loop the 'do' function for each item
for item in `echo $* | tr ',' ' '`; do
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
now=`date '+%Y-%m-%d'`
# remove priority once item is done
sed -i.bak $item"s/^(.) //" "$TODO_FILE"
sed -i.bak $item"s|^|&x $now |" "$TODO_FILE"
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item marked as done."
done
if [ $TODOTXT_AUTO_ARCHIVE = 1 ]; then
archive
fi
cleanup ;;
"help" )
help
;;
"list" | "ls" )
shift ## Was ls; new $1 is first search term
_list "$TODO_FILE" "$@"
cleanup
;;
"listall" | "lsa" )
shift ## Was lsa; new $1 is first search term
cat "$TODO_FILE" "$DONE_FILE" > "$TMP_FILE"
_list "$TMP_FILE" "$@"
cleanup
;;
"listfile" | "lf" )
shift ## Was listfile, next $1 is file name
FILE="$1"
shift ## Was filename; next $1 is first search term
_list "$FILE" "$@"
cleanup
;;
"listcon" | "lsc" )
grep -o '[^ ]*@[^ ]\+' "$TODO_FILE" | grep '^@' | sort -u
cleanup ;;
"listproj" | "lsprj" )
grep -o '[^ ]*+[^ ]\+' "$TODO_FILE" | grep '^+' | sort -u
cleanup ;;
"listpri" | "lsp" )
shift ## was "listpri", new $1 is priority to list
if [ "${1:-}" ]
then
## A priority was specified
pri=$( printf "%s\n" "$1" | tr 'a-z' 'A-Z' | grep '^[A-Z]$' ) || {
die "usage: $TODO_SH listpri PRIORITY
note: PRIORITY must a single letter from A to Z."
}
else
## No priority specified; show all priority tasks
pri="[[:upper:]]"
fi
pri="($pri)"
_list "$TODO_FILE" "$pri"
;;
"move" | "mv" )
# replace moved line with a blank line when TODOTXT_PRESERVE_LINE_NUMBERS is 1
errmsg="usage: $TODO_SH mv ITEM# DEST [SRC]"
item=$2
dest="$TODO_DIR/$3"
src="$TODO_DIR/$4"
[ -z "$item" ] && die "$errmsg"
[ -z "$4" ] && src="$TODO_FILE"
[ -z "$dest" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
if [ -f "$src" ]; then
if [ -f "$dest" ]; then
if sed -ne "$item p" "$src" | grep "^."; then
MOVEME=$(sed "$item!d" "$src")
if [ $TODOTXT_FORCE = 0 ]; then
echo "Move '$MOVEME' from $src to $dest? (y/n)"
read ANSWER
else
ANSWER="y"
fi
if [ "$ANSWER" = "y" ]; then
if [ $TODOTXT_PRESERVE_LINE_NUMBERS = 0 ]; then
# delete line (changes line numbers)
sed -i.bak -e $item"s/^.*//" -e '/./!d' "$src"
else
# leave blank line behind (preserves line numbers)
sed -i.bak -e $item"s/^.*//" "$src"
fi
echo "$MOVEME" >> "$dest"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: '$MOVEME' moved from '$src' to '$dest'."
cleanup
else
echo "TODO: No tasks moved."
fi
else
echo "$item: No such item in $src."
fi
else
echo "TODO: Destination file $dest does not exist."
fi
else
echo "TODO: Source file $src does not exist."
fi
cleanup;;
"prepend" | "prep" )
errmsg="usage: $TODO_SH prepend ITEM# \"TEXT TO PREPEND\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Prepend: "
read input
else
input=$*
fi
# Test for then set priority
if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then
priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}')
fi
# If priority isn't set prepend
if [ -z $priority ]; then
if sed -i.bak $item" s|^.*|$input &|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else
echo "TODO: Error prepending task $item."
fi
# If priority is set, remove priority, prepend and add back priority
else
if sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) $1 &|" "$TODO_FILE"; then
newtodo=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $newtodo"
else
echo "TODO: Error prepending task $item."
fi
fi
cleanup;;
"pri" | "p" )
item=$2
newpri=$( printf "%s\n" "$3" | tr 'a-z' 'A-Z' )
errmsg="usage: $TODO_SH pri ITEM# PRIORITY
note: PRIORITY must be anywhere from A to Z."
[ "$#" -ne 3 ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
[[ "$newpri" = @([A-Z]) ]] || die "$errmsg"
sed -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE" > /dev/null 2>&1
if [ "$?" -eq 0 ]; then
#it's all good, continue
sed -i.bak -e $item"s/^(.) //" -e $item"s/^/($newpri) /" "$TODO_FILE"
NEWTODO=$(sed "$item!d" "$TODO_FILE")
[ $TODOTXT_VERBOSE -gt 0 ] && echo -e "`echo "$item: $NEWTODO"`"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: $item prioritized ($newpri)."
cleanup
else
die "$errmsg"
fi;;
"replace" )
errmsg="usage: $TODO_SH replace ITEM# \"UPDATED ITEM\""
shift; item=$1; shift
[ -z "$item" ] && die "$errmsg"
[[ "$item" = +([0-9]) ]] || die "$errmsg"
todo=$(sed "$item!d" "$TODO_FILE")
[ -z "$todo" ] && die "$item: No such todo."
# Test for then set priority
if [ `sed "$item!d" "$TODO_FILE"|grep -c "^(\\w)"` -eq 1 ]; then
priority=$(sed "$item!d" "$TODO_FILE" | awk -F '\\(|\\)' '{print $2}')
fi
if [[ -z "$1" && $TODOTXT_FORCE = 0 ]]; then
echo -n "Replacement: "
read input
else
input=$*
fi
# If priority isn't set replace, if it is remove priority, replace then add priority again
if [ -z $priority ]; then
sed -i.bak $item" s|^.*|$input|" "$TODO_FILE"
else
sed -i.bak -e "$item s/^(.) //" -e "$item s|^.*|\($priority\) $1|" "$TODO_FILE"
fi
[ $TODOTXT_VERBOSE -gt 0 ] && NEWTODO=$(head -$item "$TODO_FILE" | tail -1)
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $todo"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "replaced with"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "$item: $NEWTODO"
cleanup;;
"report" )
#archive first
sed '/^x /!d' "$TODO_FILE" >> "$DONE_FILE"
sed -i.bak '/^x /d' "$TODO_FILE"
NUMLINES=$( sed -n '$ =' "$TODO_FILE" )
if [ ${NUMLINES:-0} = "0" ]; then
echo "datetime todos dones" >> "$REPORT_FILE"
fi
#now report
TOTAL=$( sed -n '$ =' "$TODO_FILE" )
TDONE=$( sed -n '$ =' "$DONE_FILE" )
TECHO=$(echo $(date +%Y-%m-%d-%T); echo ' '; echo ${TOTAL:-0}; echo ' ';
echo ${TDONE:-0})
echo $TECHO >> "$REPORT_FILE"
[ $TODOTXT_VERBOSE -gt 0 ] && echo "TODO: Report file updated."
cat "$REPORT_FILE"
cleanup;;
* )
usage
;;
esac

View File

@@ -1,2 +0,0 @@
Checkout nootloader lock fuses

View File

@@ -1,39 +0,0 @@
CHANGEFILE
----------
This is the Changefile for the development 0.3 branch of EFSL.
Recording began with EFSL-0.3.3
0.3.5
-----
* Added warning in documentation that it is outdated
* Changed structure definitions
* Implemnted full-feature cp
* Renamed some efsl-functions (all starting with EFSL_)
* Added another example for AVR.
* Updated docs on getting started on AVR.
0.3.4
-----
* Fixed avr support
* Created new avr example + makefile
* Some more work on new fsutils
0.3.3
-----
* Renamed src/core to src/base
* Implemented new hwInterface structure
Support for multiple hwEndpoints in one project
* Modified SD_SPI to work as a general protocol
* Modified Linuxfile to the new hwInterface model
* Created a new efs_configger, now supports every
combination of partitions/disc
* Implemented full support for little and big endian
machines, as well as for little and big endian
filesystems
* Created new build system, for multiple platforms,
configurable from one file
* Changes cpo to use the new library functions
* Broke both dsp & atmega support

View File

@@ -1,31 +0,0 @@
include conf/config.makefile
linux: efsl-base efsl-fs-vfat efsl-hwd-linuxfile
avr: efsl-base efsl-fs-vfat efsl-prot-sdspi efsl-hwd-atmega_sd
efsl-base:
make -C src/base/
cp src/base/efsl-base.a lib/libefsl-base.a
efsl-fs-vfat:
make -C src/fs/vfat/
cp src/fs/vfat/efsl-fs-vfat.a lib/libefsl-fs-vfat.a
efsl-prot-sdspi:
make -C src/protocols/sdcard_spi/
cp src/protocols/sdcard_spi/efsl-prot-sdspi.a lib/libefsl-prot-sdspi.a
efsl-hwd-linuxfile:
make -C src/hwdrivers/linuxfile/
cp src/hwdrivers/linuxfile/efsl-hwd-linuxfile.a lib/libefsl-hwd-linuxfile.a
efsl-hwd-atmega_sd:
make -C src/hwdrivers/atmega_spi/
cp src/hwdrivers/atmega_spi/efsl-hwd-atmega_spi.a lib/libefsl-hwd-atmega_spi.a
clean:
make -C src/base/ clean
make -C src/fs/vfat/ clean
make -C src/hwdrivers/linuxfile/ clean
make -C src/hwdrivers/atmega_spi clean
rm -rf lib/*.a

View File

@@ -1,174 +0,0 @@
#ifndef __EFSL_CONFIG_H__
#define __EFSL_CONFIG_H__
/* Hardware target
---------------
* Here you will define for what hardware-endpoint EFSL should be compiled.
* Look in interfaces.h to see what systems are supported, and add your own
* there if you need to write your own driver. Then, define the name you
* selected for your hardware there here. Make sure that you only select one
* device!
*/
/*#define HW_ENDPOINT_LINUX*/
#define HW_ENDPOINT_ATMEGA128_SD
/*#define HW_ENDPOINT_DSP_TI6713_SD*/
#define MULTIPLE_INTERFACE_SUPPORT
/* Architecture
------------
* In this section you should configure how large the default variable
* types in your system are. This is controlled in types.h in the general
* include directory. The selection you make here defines to what the various
* e(s|u)int(8,16,32) types will map.
* For 32 bit Linux : VARSIZE_LINUX32
* For 64 bit Linux : VARSIZE_LINUX64
* For AVR's : VARSIZE_ATMEGA
* For TMS67XX : VARSIZE_TMS67XX
*/
#define VARSIZE_ATMEGA
/* Memory configuration
--------------------
* Here you must configure wheter your processor can access memory byte
* oriented. All x86 processors can do it, AVR's can do it to. Some DSP
* or other microcontrollers can't. If you have an 8 bit system you're safe.
* If you are really unsure, leave the setting commented out, it will be slower
* but it will work for sure.
*/
#define BYTE_ALIGNMENT
/* Cache configuration
-------------------
* Here you must configure how much memory of cache you can/want to use.
* The number you put at IOMAN_NUMBUFFER is multiplied by 512. So 1 means
* 512 bytes cache, 4 means 2048 bytes cache. More is better.
* The number after IOMAN_NUMITERATIONS should be untouched.
* The last field (IOMAN_DO_MEMALLOC) is to tell ioman to allocate it's
* own memory in it's structure, or not. If you choose to do it yourself
* you will have to pass a pointer to the memory as the last argument of
* ioman_init.
*/
#define IOMAN_NUMBUFFER 1
#define IOMAN_NUMITERATIONS 3
#define IOMAN_DO_MEMALLOC
/* Cluster pre-allocation
----------------------
* When writing files, the function that performs the actual write has to
* calculate how many clusters it will need for that request. It then allocates
* that number of new clusters to the file. Since this involves some
* calculations and writing of the FAT, you might find it beneficial to limit
* the number of allocations, and allow fwrite to pre-allocate a number of
* clusters extra. This setting determines how many clusters will be extra
* allocated whenever this is required.
* Take in carefull consideration how large your clustersize is, putting 10 here
* with a clustersize of 32kb means you might waste 320 kb.
* The first option is for preallocating files, the other is used when enlarging
* a directory to accomodate more files
*/
#define CLUSTER_PREALLOC_FILE 0
#define CLUSTER_PREALLOC_DIRECTORY 0
/* Endianess configuration
-----------------------
* Here you can configure wheter your architecture is little or big endian. This
* is important since all FAT structures are stored in intel little endian
* order. So if you have a big endian system the library has to convert all
* figures to big endian in order to work.
*/
#define HOST_LITTLE_ENDIAN
/* Date and Time support
---------------------
* Here you can enable or disable date and time support. If you enable
* it you will have to create 6 functions, that are described in the
* EFSL manual. If the functions are not present when linking your
* program with the library you will get unresolved dependencies.
*/
/* #define DATE_TIME_SUPPORT */
/* Error reporting support
-----------------------
* When you receive an error in userland, it usually only gives limited
* information (most likely, fail or success). If error detection and
* reporting is important for you, you can enable more detailed error
* reporting here. This is optional, the costs are 1 byte per object,
* and a small increase in code size.
* You can enable error recording for all object, or you can select the
* object manually.
* For full error reporting use FULL_ERROR_SUPPORT
* For only the base-core of the library use BASE_ERROR_SUPPORT
* For IO/Man use ERRSUP_IOMAN
* For Disc use ERRSUP_IOMAN
* For Part use ERRSUP_PARTITION
* For Fs use ERRSUP_FILESYSTEM
* For File use ERRSUP_FILE
*/
#define FULL_ERROR_SUPPORT
/*#define BASE_ERROR_SUPPORT*/
/* List options
------------
* In this section you can configure what kind of data you will get from
* directory listing requests. Please refer to the documentation for
* more information
*/
#define LIST_MAXLENFILENAME 12
/* Debugging configuration
-----------------------
* Here you can configure the debugging behaviour. Debugging is different
* on every platform (see debug.h for more information).
* If your hardware has no means of output (printf) dont define any anything,
* and nothing will happen. For real world use debugging should be turned off.
*/
#define DEBUG
/* Debugging configuration - AVR Specific: PORT
--------------------------------------------
* Here you can select which UART you want to use for debugging.
* If you did not define DEBUG, this setting has no effect.
* Note that it is not a good idea to use a port that you use in userspace.
*/
/*#define DEBUG_PORT 0*/ /* Select UART0 */
#define DEBUG_PORT 1 /* Select UART1 */
/* Debugging configuration - AVR Specific: UBRR
--------------------------------------------
* Here you can set UBRR, this value will select the serial clock speed.
* This value depends on your baudrate and clockrate. U2X is by standard 0,
* if you would want this 1 for some reason, this can be done in debug.c.
*/
/*#define DEBUG_UBRR 51*/ /* 9600bps on 8Mhz */
#define DEBUG_UBRR 95 /* 9600bps on 14.7456Mhz */
/*#define DEBUG_UBRR 103*/ /* 9600bps on 16Mhz */
#endif

View File

@@ -1,46 +0,0 @@
################################################################################
### EFSL - Embedded Filesystems Library ###
### ----------------------------------- ###
### ###
################################################################################
# This is the configuration file for EFSL. This file will enable your to build
# the library if you have GNU make, or compatible, on your system.
# If you do not have a make utility on your system, or it cannot be used in this
# fashion (when using IDE's, like MSVC or Code composer), please refer to the
# documentation on how to build EFSL. It is possible to build EFSL with any C
# compiler although it will be a bit more work.
# C compiler
# ----------
#
# Here you select with what binary the sourcefiles must be compiled
CC=avr-gcc
# AR archiver
# -----------
#
# This variable controls what archiver is to be used. This utility is optional,
# if you don't have GNU make, you probably need to link differently as well.
AR=avr-ar
# Objcopy
# --------
#
# This variable controls what objcopy is to be used. This utility will be used
# when the program is converted to an format that your uC understands.
OBJCOPY=avr-objcopy
# C compiler options
# ------------------
#
# Here you can configure several options about the compilation.
DEBUGGING=-g3
VERIFY=-Wall
ARCHITECTURE=-mmcu=atmega128
OPTIMISE=-Os
GCFLAGS=$(DEBUGGING) $(VERIFY) $(ARCHITECTURE) $(OPTIMISE)

View File

@@ -1,151 +0,0 @@
#ifndef __EFSL_CONFIG_H__
#define __EFSL_CONFIG_H__
/* Hardware target
---------------
* Here you will define for what hardware-endpoint EFSL should be compiled.
* Look in interfaces.h to see what systems are supported, and add your own
* there if you need to write your own driver. Then, define the name you
* selected for your hardware there here. Make sure that you only select one
* device!
*/
/*#define HW_ENDPOINT_LINUX*/
/*#define HW_ENDPOINT_ATMEGA128_SD*/
/*#define HW_ENDPOINT_DSP_TI6713_SD*/
#define MULTIPLE_INTERFACE_SUPPORT
/*#define HWIFUNC_INIT(x) lf_init(x)
#define HWIFUNC_READ(x,y,z) lf_readBuf(x,y,z)
#define HWIFUNC_WRITE(x,y,z) lf_writeBuf(x,y,z)
#define HWIFUNC_HEADER interfaces/linuxfile.h */
/* Architecture
------------
* In this section you should configure how large the default variable
* types in your system are. This is controlled in types.h in the general
* include directory. The selection you make here defines to what the various
* e(s|u)int(8,16,32) types will map.
* For 32 bit Linux : VARSIZE_LINUX32
* For 64 bit Linux : VARSIZE_LINUX64
* For AVR's : VARSIZE_ATMEGA
* For TMS67XX : VARSIZE_TMS67XX
*/
#define VARSIZE_LINUX32
/* Memory configuration
--------------------
* Here you must configure wheter your processor can access memory byte
* oriented. All x86 processors can do it, AVR's can do it to. Some DSP
* or other microcontrollers can't. If you have an 8 bit system you're safe.
* If you are really unsure, leave the setting commented out, it will be slower
* but it will work for sure.
*/
#define BYTE_ALIGNMENT
/* Cache configuration
-------------------
* Here you must configure how much memory of cache you can/want to use.
* The number you put at IOMAN_NUMBUFFER is multiplied by 512. So 1 means
* 512 bytes cache, 4 means 2048 bytes cache. More is better.
* The number after IOMAN_NUMITERATIONS should be untouched.
* The last field (IOMAN_DO_MEMALLOC) is to tell ioman to allocate it's
* own memory in it's structure, or not. If you choose to do it yourself
* you will have to pass a pointer to the memory as the last argument of
* ioman_init.
*/
#define IOMAN_NUMBUFFER 10
#define IOMAN_NUMITERATIONS 3
#define IOMAN_DO_MEMALLOC
/* Cluster pre-allocation
----------------------
* When writing files, the function that performs the actual write has to
* calculate how many clusters it will need for that request. It then allocates
* that number of new clusters to the file. Since this involves some
* calculations and writing of the FAT, you might find it beneficial to limit
* the number of allocations, and allow fwrite to pre-allocate a number of
* clusters extra. This setting determines how many clusters will be extra
* allocated whenever this is required.
* Take in carefull consideration how large your clustersize is, putting 10 here
* with a clustersize of 32kb means you might waste 320 kb.
* The first option is for preallocating files, the other is used when enlarging
* a directory to accomodate more files
*/
#define CLUSTER_PREALLOC_FILE 5
#define CLUSTER_PREALLOC_DIRECTORY 2
/* Endianess configuration
-----------------------
* Here you can configure wheter your architecture is little or big endian. This
* is important since all FAT structures are stored in intel little endian
* order. So if you have a big endian system the library has to convert all
* figures to big endian in order to work.
*/
/*#define HOST_BIG_ENDIAN*/
#define HOST_LITTLE_ENDIAN
/* Date and Time support
---------------------
* Here you can enable or disable date and time support. If you enable
* it you will have to create 6 functions, that are described in the
* EFSL manual. If the functions are not present when linking your
* program with the library you will get unresolved dependencies.
*/
/* #define DATE_TIME_SUPPORT */
/* Error reporting support
-----------------------
* When you receive an error in userland, it usually only gives limited
* information (most likely, fail or success). If error detection and
* reporting is important for you, you can enable more detailed error
* reporting here. This is optional, the costs are 1 byte per object,
* and a small increase in code size.
* You can enable error recording for all object, or you can select the
* object manually.
* For full error reporting use FULL_ERROR_SUPPORT
* For only the base-core of the library use BASE_ERROR_SUPPORT
* For IO/Man use ERRSUP_IOMAN
* For Disc use ERRSUP_IOMAN
* For Part use ERRSUP_PARTITION
* For Fs use ERRSUP_FILESYSTEM
* For File use ERRSUP_FILE
*/
#define FULL_ERROR_SUPPORT
/*#define BASE_ERROR_SUPPORT*/
/* Debugging configuration
-----------------------
* Here you can configure the debugging behaviour. Debugging is different
* on every platform (see debug.h for more information).
* If your hardware has no means of output (printf) dont define any anything,
* and nothing will happen. For real world use debugging should be turned off.
*/
/*#define DEBUG*/
/*#define DO_FUNC_DEBUG*/
/* List options
------------
* In this section you can configure what kind of data you will get from
* directory listing requests. Please refer to the documentation for
* more information
*/
#define LIST_MAXLENFILENAME 12
#endif

View File

@@ -1,38 +0,0 @@
################################################################################
### EFSL - Embedded Filesystems Library ###
### ----------------------------------- ###
### ###
################################################################################
# This is the configuration file for EFSL. This file will enable your to build
# the library if you have GNU make, or compatible, on your system.
# If you do not have a make utility on your system, or it cannot be used in this
# fashion (when using IDE's, like MSVC or Code composer), please refer to the
# documentation on how to build EFSL. It is possible to build EFSL with any C
# compiler although it will be a bit more work.
# C compiler
# ----------
#
# Here you select with what binary the sourcefiles must be compiled
CC=gcc
# AR archiver
# -----------
#
# This variable controls what archiver is to be used. This utility is optional,
# if you don't have GNU make, you probably need to link differently as well.
AR=ar
# C compiler options
# ------------------
#
# Here you can configure several options about the compilation.
DEBUGGING=-g3
VERIFY=-Wall -pedantic -ansi
ARCHITECTURE=-march=i386
OPTIMISE=-O0
GCFLAGS=$(DEBUGGING) $(VERIFY) $(ARCHITECTURE) $(OPTIMISE)

View File

@@ -1,151 +0,0 @@
#ifndef __EFSL_CONFIG_H__
#define __EFSL_CONFIG_H__
/* Hardware target
---------------
* Here you will define for what hardware-endpoint EFSL should be compiled.
* Look in interfaces.h to see what systems are supported, and add your own
* there if you need to write your own driver. Then, define the name you
* selected for your hardware there here. Make sure that you only select one
* device!
*/
/*#define HW_ENDPOINT_LINUX*/
/*#define HW_ENDPOINT_ATMEGA128_SD*/
/*#define HW_ENDPOINT_DSP_TI6713_SD*/
#define MULTIPLE_INTERFACE_SUPPORT
/*#define HWIFUNC_INIT(x) lf_init(x)
#define HWIFUNC_READ(x,y,z) lf_readBuf(x,y,z)
#define HWIFUNC_WRITE(x,y,z) lf_writeBuf(x,y,z)
#define HWIFUNC_HEADER interfaces/linuxfile.h */
/* Architecture
------------
* In this section you should configure how large the default variable
* types in your system are. This is controlled in types.h in the general
* include directory. The selection you make here defines to what the various
* e(s|u)int(8,16,32) types will map.
* For 32 bit Linux : VARSIZE_LINUX32
* For 64 bit Linux : VARSIZE_LINUX64
* For AVR's : VARSIZE_ATMEGA
* For TMS67XX : VARSIZE_TMS67XX
*/
#define VARSIZE_LINUX64
/* Memory configuration
--------------------
* Here you must configure wheter your processor can access memory byte
* oriented. All x86 processors can do it, AVR's can do it to. Some DSP
* or other microcontrollers can't. If you have an 8 bit system you're safe.
* If you are really unsure, leave the setting commented out, it will be slower
* but it will work for sure.
*/
#define BYTE_ALIGNMENT
/* Cache configuration
-------------------
* Here you must configure how much memory of cache you can/want to use.
* The number you put at IOMAN_NUMBUFFER is multiplied by 512. So 1 means
* 512 bytes cache, 4 means 2048 bytes cache. More is better.
* The number after IOMAN_NUMITERATIONS should be untouched.
* The last field (IOMAN_DO_MEMALLOC) is to tell ioman to allocate it's
* own memory in it's structure, or not. If you choose to do it yourself
* you will have to pass a pointer to the memory as the last argument of
* ioman_init.
*/
#define IOMAN_NUMBUFFER 10
#define IOMAN_NUMITERATIONS 3
#define IOMAN_DO_MEMALLOC
/* Cluster pre-allocation
----------------------
* When writing files, the function that performs the actual write has to
* calculate how many clusters it will need for that request. It then allocates
* that number of new clusters to the file. Since this involves some
* calculations and writing of the FAT, you might find it beneficial to limit
* the number of allocations, and allow fwrite to pre-allocate a number of
* clusters extra. This setting determines how many clusters will be extra
* allocated whenever this is required.
* Take in carefull consideration how large your clustersize is, putting 10 here
* with a clustersize of 32kb means you might waste 320 kb.
* The first option is for preallocating files, the other is used when enlarging
* a directory to accomodate more files
*/
#define CLUSTER_PREALLOC_FILE 5
#define CLUSTER_PREALLOC_DIRECTORY 2
/* Endianess configuration
-----------------------
* Here you can configure wheter your architecture is little or big endian. This
* is important since all FAT structures are stored in intel little endian
* order. So if you have a big endian system the library has to convert all
* figures to big endian in order to work.
*/
/*#define HOST_BIG_ENDIAN*/
#define HOST_LITTLE_ENDIAN
/* Date and Time support
---------------------
* Here you can enable or disable date and time support. If you enable
* it you will have to create 6 functions, that are described in the
* EFSL manual. If the functions are not present when linking your
* program with the library you will get unresolved dependencies.
*/
/* #define DATE_TIME_SUPPORT */
/* Error reporting support
-----------------------
* When you receive an error in userland, it usually only gives limited
* information (most likely, fail or success). If error detection and
* reporting is important for you, you can enable more detailed error
* reporting here. This is optional, the costs are 1 byte per object,
* and a small increase in code size.
* You can enable error recording for all object, or you can select the
* object manually.
* For full error reporting use FULL_ERROR_SUPPORT
* For only the base-core of the library use BASE_ERROR_SUPPORT
* For IO/Man use ERRSUP_IOMAN
* For Disc use ERRSUP_IOMAN
* For Part use ERRSUP_PARTITION
* For Fs use ERRSUP_FILESYSTEM
* For File use ERRSUP_FILE
*/
#define FULL_ERROR_SUPPORT
/*#define BASE_ERROR_SUPPORT*/
/* Debugging configuration
-----------------------
* Here you can configure the debugging behaviour. Debugging is different
* on every platform (see debug.h for more information).
* If your hardware has no means of output (printf) dont define any anything,
* and nothing will happen. For real world use debugging should be turned off.
*/
/*#define DEBUG*/
/*#define DO_FUNC_DEBUG*/
/* List options
------------
* In this section you can configure what kind of data you will get from
* directory listing requests. Please refer to the documentation for
* more information
*/
#define LIST_MAXLENFILENAME 12
#endif

View File

@@ -1,38 +0,0 @@
################################################################################
### EFSL - Embedded Filesystems Library ###
### ----------------------------------- ###
### ###
################################################################################
# This is the configuration file for EFSL. This file will enable your to build
# the library if you have GNU make, or compatible, on your system.
# If you do not have a make utility on your system, or it cannot be used in this
# fashion (when using IDE's, like MSVC or Code composer), please refer to the
# documentation on how to build EFSL. It is possible to build EFSL with any C
# compiler although it will be a bit more work.
# C compiler
# ----------
#
# Here you select with what binary the sourcefiles must be compiled
CC=gcc
# AR archiver
# -----------
#
# This variable controls what archiver is to be used. This utility is optional,
# if you don't have GNU make, you probably need to link differently as well.
AR=ar
# C compiler options
# ------------------
#
# Here you can configure several options about the compilation.
DEBUGGING=-g3
VERIFY=-Wall -pedantic -ansi
ARCHITECTURE=-march=k8
OPTIMISE=-O0
GCFLAGS=$(DEBUGGING) $(VERIFY) $(ARCHITECTURE) $(OPTIMISE)

View File

@@ -1 +0,0 @@
config-linux.h

View File

@@ -1 +0,0 @@
config-linux.makefile

View File

@@ -1,13 +0,0 @@
all: manual.tex
latex manual.tex
latex manual.tex # Needs to be done a second time to make sure that the contents table is correct
dvips -o manual.ps manual.dvi
dvipdfm manual.dvi
clean:
rm -f manual.aux
rm -f manual.dvi
rm -f manual.log
rm -f manual.pdf
rm -f manual.ps
rm -f manual.toc

File diff suppressed because it is too large Load Diff

View File

@@ -1,117 +0,0 @@
\documentclass[a4paper,fleqn]{article}
\usepackage{listings}
\usepackage{graphicx}
\usepackage{amsmath}
\usepackage{amssymb}
\usepackage{color}
\usepackage{array}
\usepackage{verbatim}
\usepackage{longtable}
\newcommand{\filename}[1]{
\textsf{#1}
}
\newcommand{\code}[1]{
\texttt{#1}
}
\newcommand{\external}[1]{
\textbf{#1}
}
\newcommand{\thead}[1]{
\textbf{#1}
}
%\usepackage[latin1]{inputenc}
%\usepackage[T1]{fontenc}
\lstset{language=C}
\begin{document}
\title{\Huge{EFSL}\\\Large{Embedded Filesystems Library - 0.3}}
\author{Lennart Yseboodt\\Michael De Nil}
\date{$\copyright$ 2005}
\maketitle
\newpage
\tableofcontents
\setlength{\parindent}{0pt}
\setlength{\parskip}{1ex plus 0.5ex minus 0.2ex}
\newpage
\section{Document Outdated!}
{\Huge{
This document is outdated and is in the progress of being renewed.\\
\newline\newline
If you are just starting with Efsl, we recommend you to start with the stable
0.2-branch. This version is currently not really usable, and is intended for people
working on the code.
}}
\newpage
\section{Preface}
\input{pages/preface}
\newpage
\section{Getting started}
\subsection{On Linux (file) (0.2)}
\input{pages/linux}
\newpage
\subsection{On AVR (SD-Card) (0.3)}
\input{pages/avr}
\newpage
\subsection{On DSP (SD-Card) (0.2)}
\input{pages/tms6713}
\newpage
\section{Configuring EFSL (0.2)}
\input{pages/config}
\newpage
\section{EFSL Functions}
\subsection{Date and time support (0.2)}
\input{pages/dateandtime}
\newpage
\subsection{efs\_init (0.2)}
\input{pages/efs_init}
\newpage
\subsection{file\_fopen (0.2)}
\input{pages/file_fopen}
\newpage
\subsection{file\_fclose (0.2)}
\input{pages/file_fclose}
\newpage
\subsection{file\_read (0.2)}
\input{pages/file_read}
\newpage
\subsection{file\_write (0.2)}
\input{pages/file_write}
\newpage
\subsection{mkdir (0.2)}
\input{pages/mkdir}
\newpage
\subsection{ls\_openDir (0.2)}
\input{pages/lsopendir}
\newpage
\subsection{ls\_getNext (0.2)}
\input{pages/lsgetnext}
\newpage
\newpage
\section{Developer notes}
\subsection{Integer types (0.2)}
\input{pages/types}
\subsection{Debugging (0.2)}
\input{pages/debug}
\subsection{Adding support for a new endpoint (0.2)}
\input{pages/driver}
\subsection{I/O Manager (0.2)}
\input{pages/ioman}
\subsection{C library for EFSL (0.2)}
\input{pages/plibc}
\newpage
\section{Legal notes}
\input{pages/license}
\end{document}

View File

@@ -1,223 +0,0 @@
This section describes how to implement Efsl on a AVR $\mu C$ connected to
an SD-Card (SPI). For getting efsl to compile, the avr-gcc compiler and
avr-libc library are required. On Windows you should install WinAVR
(http://winavr.sourceforge.net/), on Linux you can install the packages
separately (see http://www.nongnu.org/avr-libc/user-manual/install\_tools.html
for a nice howto).
\subsubsection{Hardware}
First, you need set up a prototype in which you connect the CD, CMD, DAT0
\& CLK lines from the SD-Card to /CS, MOSI, MISO \& SCK from the Atmega.
\newline
\includegraphics[scale=0.65]{pics/sdcard.eps}
\newline
%\parbox[c]{.4\textwidth}{\begin{center}\includegraphics[width=.4\textwidth]{pics/sdconnection}\end{center}}
\parbox[c]{.5\textwidth}{
Connect the following lines on the SD-card:
\begin{itemize}
\item{Pin 9 (DAT2) - NC\\(or pull-up to 3.3V)}
\item{Pin 1 (CD) - Any pin on the Atmega128}
\item{Pin 2 (CMD) - MOSI\\(pin 12 on the Atmega128)}
\item{Pin 3 (Vss) - GND}
\item{Pin 4 (Vdd) - +3.3V}
\item{Pin 5 (CLK) - SCK\\(pin 11 on the Atmega128)}
\item{Pin 6 (Vss) - GND}
\item{Pin 7 (DAT0) - MISO\\(pin 12 on the Atmega128)}
\item{Pin 8 (DAT1) - NC\\(or pull-up to 3.3V)}
\end{itemize}
}
\parbox[c]{.5\textwidth}{\begin{center}
\includegraphics[width=.5\textwidth]{pics/sdconnection}
\newline\newline
Remark: this schematic includes pull-up's to 3.3V, which
can be left off.
\end{center}}
\newline
Remark 1: Make sure that your $\mu C$ is running on 3,3V, so you don't
damage your SD-Card.\newline
\newline
Remark 2: CD is currently static set to PB0, but will become variable
in future releases.
\subsubsection{Download \& Compile}
Let's get started:
\begin{enumerate}
\item{Get the latest release of efsl on http://www.sf.net/projects/efsl/}
\item{Unpack the library (on Windows, you can use WinACE or WinRAR)}
\item{Copy in directory \filename{conf} the file
\filename{config-avr.h} to \filename{config.h}}
\item{Copy in directory \filename{conf} the file
\filename{config-avr.makefile} to \filename{config.makefile}}
\item{Compile the library (\code{make avr})}
\end{enumerate}
Now you should have the following files in a directory called {lib}:
\begin{itemize}
\item{\filename{libefsl-base.a}}
\item{\filename{libefsl-fs-vfat.a}}
\item{\filename{libefsl-prot-sdspi.a}}
\item{\filename{libefsl-hwd-atmega\_spi.a}}
\end{itemize}
\subsubsection{Example}
Since Efsl itself is only a library, it's not supposed to do anything out of
the box, than just compile. To get started, we'll show here a small example
program that opens an existing file and writes the content to a new file.
\newline\newline
First, create a new directory in which you put the compiled efsl-library
(\filename{libefsl.a}) and create a new file called \filename{avrtest.c} containing:
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include <efs.h>
#include <sd.h>
#include <atmega_spi.h>
void hang(void);
void main(void)
{
efsl_storage_conf storage_conf;
efsl_fs_conf fs_conf;
efsl_storage storage;
efsl_fs fs;
File file_r;
File file_w;
atmegaSpiInterface spi_interface;
SdSpiProtocol sd_protocol;
char buf[512];
unsigned short e;
/* Init */
spi_interface.pinSelect=0x01;
sd_protocol.spiHwInterface=&spi_interface;
sd_protocol.spiHwInit=(void *)atmega_spi_init;
sd_protocol.spiSendByte=(void *)atmega_spi_send;
storage_conf.hwObject=&sd_protocol;
storage_conf.if_init_fptr=(void *)sd_Init;
storage_conf.if_read_fptr=(void *)sd_readSector;
storage_conf.if_write_fptr=(void *)sd_writeSector;
storage_conf.if_ioctl_fptr=(void *)sd_ioctl;
storage_conf.ioman_bufmem=0;
fs_conf.no_partitions=0;
fs_conf.storage=&storage;
if(efsl_initStorage(&storage,&storage_conf)){
hang();
}
if(efsl_initFs(&fs,&fs_conf)){
hang();
}
if(file_fopen(&file_r,&fs.filesystem,"orig.txt",'r')!=0){
hang();
}
if(file_fopen(&file_w,&fs.filesystem,"copy.txt",'w')!=0){
hang();
}
if(file_fopen(&file_r,&efs.myFs,"orig.txt",'r')!=0){
hang();
}
while((e=file_read(&file_r,512,buf))){
file_write(&file_w,e,buf);
}
file_fclose(&file_r);
file_fclose(&file_w);
fs_umount(&fs.filesystem);
hang();
}
void hang(void)
{
while((1))
_NOP();
}
\end{lstlisting}
$ $\newline
Some extra information on the code above: TODO
%\begin{itemize}
% \item{Line 1: The header file for efsl is included here. When using the
% basic efsl functions, \filename{efs.h} is the only header file on the
% efsl library that needs to be included.}
% \item{Line 7: The object efs is created, this object will contain
% information about the hardware layer, the partition table and
% the disc.}
% \item{Line 8: The objects \code{file\_r} and \code{file\_w} are created, these objects
% will contain information about the files that we will open on the
% efs-object.}
% \item{Line 9: A buffer of 512 bytes is allocated. This buffer will be
% used for reading and writing blocks of data.}
% \item{Line 12: Call of \code{efs\_init()}, which will initialize the efs-object.
% To this function we pass:
% \begin{enumerate}
% \item{A pointer to the efs-object.}
% \item{A pointer to the file that contains the partition table /
% file system (in this example, we select a device as file).}
% \end{enumerate}
% If this function returns 0, it means that a valid fat partition is
% found on the SD-card connected.
% If no valid fat-filesystem is found, or the file does not exist, the
% function returns a negative value. In this example we then go to an
% infinite loop to prevent the program to continue.}
% \item{Line 16 \& 20: Call of \code{file\_fopen()}, which will initialize the
% file-objects. To this function we pass:
% \begin{enumerate}
% \item{A pointer to the file-object.}
% \item{A pointer to the filesystem-object.}
% \item{A pointer to the filename.}
% \item{A char containing the the mode (read, write, append).}
% \end{enumerate}
% If this function returns 0, it means the file has successfully been
% opened for reading / writing / appending.
% If the file could not be opened (because for example a file already
% exists), a negative value is returned.}
% \item{Line 24: Call of \code{file\_read()}, which will read a given value of
% bytes (in this example 512) from a file and put it's content into
% the buffer passed (in this example called buf). This function returns
% the amount of bytes read, so the while-loop will be executed as long
% as there are bytes left in the file.}
% \item{Line 25: Call of \code{file\_write()}, which will write a given value
% of bytes (in this example, the amount of bytes that was read
% by \code{file\_read()}) from the buffer passed to a file. This function returns
% the amount of bytes written.}
% \item{Line 28 \& 29: Call of \code{file\_fclose()}, which will close the
% file-objects.}
% \item{Line 31: Call of \code{fs\_umount()}, which will write all buffers to
% the the SD-card.}
%\end{itemize}
\subsubsection{Testing}
So now let's test the program:
\begin{enumerate}
\item
{ Compile the program:
\begin{itemize}
\item{On Linux (with avr-gcc): avr-gcc -I/home/user/src/base/include -I/home/user/src/include -I/home/user/src/fs/vfat/include -I/home/user/src/hwdrivers/atmega\_spi/include -I/home/user/src/protocols/sdcard\_spi/include -I/home/user/conf -ffreestanding -mmcu=atmega128 -Os -o avrtest.o avrtest.c -L/home/user/lib -lefsl-base -lefsl-fs-vfat -lefsl-hwd-atmega\_spi -lefsl-prot-sdspi}
\item{On Windows (with WinAVR): replace all slashes with backslashes}
\end{itemize}
}
\item{Generate a hexfile
(avr-objcopy -j .text -j .data -O ihex avrtest.o avrtest.hex)}
\item{Connect an SD-card to your Atmega128 with a file called
\filename{orig.txt} on it.}
\item
{
Flash the hex file into your $\mu C$.
\begin{itemize}
\item{On Linux: avrdude -P /dev/ttyUSB0 -c stk500 -p m128 -Uflash:w:avrtest.hex}
\item{On Windows: use Atmel AVR-Studio}
\end{itemize}
}
\item{Reset your $\mu C$ and wait some time (depending on how big
the file \filename{orig.txt} is).}
\item{Disconnect the SD-card, so you can put it in your card reader
and find out if the file \filename{orig.txt} is copied to
\filename{copy.txt}.}
\end{enumerate}

View File

@@ -1,180 +0,0 @@
In this section we're going to talk about the configuration file (\filename{config.h}),
that defines the behavior of the library. In the configuration files there are many
settings, most of which default to safe or 'standard' compliant settings.
For every platform we try to deliver a sample configuration, with setting tweaked for
that architecture. This documentation only refers to the general elements which are
tied to the library rather that the target hardware.
\subsection{Hardware target}
Here you will define what kind of hardware you will be using. Please refer to
section \ref{hwdriver} to learn how to write a hardware endpoint.
Here you must \code{\#define} the name of your hardware endpoint.
The following list contains the endpoints that the library ships with.\\
\begin{tabular}{|l|p{8cm}|}
\hline
\code{HW\_ENDPOINT\_LINUX}& This endpoint uses a regular file as
a "disc" containing a filesystem. This is a great endpoint for
testing and debugging. All development is done using this emulation.\\
\code{HW\_ENDPOINT\_ATMEGA128\_SD}& This endpoint is for the Atmel ATMega 128
with an SD card attached to the SPI pins of the device. Several settings
that are specific for this endpoint can be found in the AVR sample
configuration. A Makefile is also provided for compiling the EFSL library
using avr-gcc.\\
\code{HW\_ENDPOINT\_DSP\_TI6713\_SD}& This endpoint is for a TI DSP, it should
work with any McBSP port, due to the infinite amount of options, you should
refer to the source code of this endpoint for fine tuning, or selecting what
port to use (defaults to McBSP0).\\
\hline
\end{tabular}
\subsection{Memory configuration}
This section only has one option, called \code{BYTE\_ALIGNMENT}. If you define
this keyword the library will assume that your CPU is capable of accessing the
memory in any way it sees fit. This is the case on AVR, because they are 8 bit
processors, and it is also the case on Intel x86 hardware. Both architectures
can read and write words, or double words on any location in memory, be it
word aligned or not.
However, some CPU's, are not capable of doing this, and require that all double words
are aligned on a double word boundary, and all word are aligned on a word boundary.
This causes problems with some of the casts that are performed in EFSL. If you have such
a CPU, then you must comment this option out. The effect is that special functions
will be used to copy or cast memory. These functions work around the problem by
using memCpy, or manually copying elements of the structs that are normally cast when
\code{BYTE\_ALIGNMENT} is defined.
If you have an 8 bit architecture, or are running on PC, there is no need to turn this
off. If you do, the library will work fine, and maybe even without slowdown.
On architectures that do have the alignment problem, you should turn this flag off.
Failure to do so will result in undefined behavior.
\subsection{Cache configuration}
This section is dedicated to configuring the cache memory for the library. Caching
is performed by the IOMan object, see section \ref{ioman}.
\subsubsection*{IOMAN\_NUMBUFFER}
This number determines how much memory will be used for caching. Since this
is sector based one \code{IOMAN\_NUMBUFFER} equals to 512 byes of memory, plus
a small overhead in settings (approximately 8 bytes). This number is also affected
by \code{IOMAN\_NUMITERATIONS}.
You should carefully consider how much memory you will dedicate to caching. A too
low number will cause excessive data transfer to and from the disc, where a too high
number will simply be a waste of memory.
A good rule of thumb is to use 1 buffer per filesystem you create, and 2 buffers
per file you want to use simultaneously. So for a simple application with
one filesystem, and one file operation, 2 or 3 buffers will be fine. If you have memory
to spare, you can use 6 buffers. Using more buffers will have a minimal effect on
performance.
If you want to seek and rewrite portions of a file, add an extra buffer for that file.
Using the list function or creating directories will be disc intensive, try to smoothen
it by using an extra 3 buffer for either operation.
It is perfectly possible to have multiple files op for reading and writing, on different
filesystems, with listing etc and only using 1 buffer. It will be a tough blow on
performance though.
\subsubsection*{IOMAN\_NUMITERATION}
This number controls how many stack places each cache place gets. Refer to the IOMan
section for an explanation. In short, if you only have 1 buffer, leave it at 3. If you
use more than 4 buffers try decreasing the number to 2 or 1 for a small memory gain.
If you get errors, it means you have set it too low (see error support). It is best
to leave this at the default setting (do not increase it), unless you know what you
are doing.
\subsubsection*{IOMAN\_DOMEMALLOC}
This configures how IOMan will get it's memory. If you leave it enable, the memory
will be allocated by IOMan itself. That means that when you declare the IOMan object
it will have a member the size of $512 \cdot \mathrm{IOMAN\_NUMBUFFER}$.
That also means that that huge lump of memory will reside on the stack. On a true embedded platform with no malloc, this is your best option.
The last argument of \code{ioman\_init} will be ignored.
If you comment this out,IOMan will take a \code{euint8*} pointer as it's third
argument to \code{ioman\_init}. It will use the memory pointed to as cache.
You will have to make sure it's reserved and of the correct size.
This allows you to put the memory on the heap, or perform special tricks like
deallocating it without having to umount your filesystem and open files.
On systems with malloc, this is the recommended setting.
If you use the efs wrapper object, please look at the \code{efs\_init} documentation
on how to pass the ioman pointer.
\subsection{Pre-allocation}
Our VFAT module supports the concept of pre-allocation. When writing files, for
example log files, it is usually done with tiny bits a time. That is not the
most efficient way, but it is usually the only solution that works on embedded
systems. Every time you cross a cluster boundary with your write, the library
has to search a new cluster (reading the FAT), allocate it (write to the FAT).
Clearly, this is a waste. The solution we came up with was preallocating. This means
that when you write to a file, and fwrite sees that it needs to allocate more clusters,
it will allocate too many of them. Since this is done in one operation, it requires
usually only one read and one write to the FAT. This can save up to 50\% disc I/O
in some applications.
The drawback is that the allocation happens in larger chunks, if you do this with
many files, you might end up with larger than normal amounts of slackspace.
We have also implemented this feature for directories. This is very useful if you
have to create a lot of small files, since the directories grow by larger portions
then.
\subsubsection*{CLUSTER\_PREALLOC\_FILE}
This number determines the default value of extra clusters that will be allocated
with every sizeincrease. For example, if fwrite calculates that it needs 7 clusters,
and \code{CLUSTER\_PREALLOC\_FILE} is 30 then efsl will allocate 37 clusters.
This means (assuming every write needs 7 clusters) that the next 4 writes won't
require any write operation to the FAT (and due to the cluster cache the FAT will probably have to be read only once).
The value you put here will be the default value, it can be changed per file
object. (not yet implemented).
\subsubsection*{CLUSTER\_PREALLOC\_DIRECTORY}
The same explanation as above counts, only this value is used for directories.
Generally you should not put this above 10 (unless your speed tests prove otherwise
off course).
\subsection{Endianness}
The Microsoft FAT filesystem was originally created to be run on Intel compatible hardware.
Therefore the Microsoft programmers decided to record all data on the disc in little endian
format. Our library supports running on big endian devices. Here you can select whether your
target CPU is little or big endian.
Running on big endian will cause some performance lose because (rather simple) calculations have
to be made to all numbers that have to interpreted by the library. This does not apply to
data within the files off course.
If the flag \code{\#LITTLE\_ENDIAN} is set, efsl will assume that your hardware is little endian.
If you have a big endian system, you should comment this out. The function \code{fs\_checkEndian}
will tell you if you have selected the right endianness, this is a check you might want to use.
\subsection{Date and time}
This flag determines if you want to have date and time support. With date and time support we
mean that when you create or update a file the directory entry will receive the correct date and
time stamp.
Please refer to section \ref{dateandtime} to learn more about how this works.
If you disable date and time support by commenting the \code{\#DATE\_TIME\_SUPPORT} then
all dates and times that need to be created or updated will be set to zero, which in FAT land corresponds to the first of January of the year 1970.
\subsection{Errors}
When the library encounters an error, there be an error cascade moving from the error-causing object
to the topmost object where the request started. Seen from userland this gives you extremely little
information, usually nothing more than fail or success.
Every object in the library has an optional error field, that contains a unique number that
corresponds to a specific error. If you examine every error field you can see exactly where the
error was started and what the effect was on the higher level objects.
In a more practical sense you can display an error number or explanation to your users, giving
yourself or them a better chance to correct or avoid the problem.
Please see the section on error on what every value means.
\subsection{Debug}
This will turn debug support on or off. When enable (and your platform has a means of output that
is supported by EFSL) it you will see messages you have created yourself, or that are printed by the
library. By default the library is very silent, only very critical errors might get printed out.
This option is depreciated and is left in for backward compatibility.

View File

@@ -1,34 +0,0 @@
\label{dateandtime}
The EFSL library supports setting and updating all date and time fields
supported by the filesystem. In order to do this the library must
know the current time and date at all times. Since it has to run everywhere,
there is no standard mechanism to get the date/time, and some systems do
not have a clock.
With default configuration there is no date or time support, you have to
turn it on manually in the configuration file \filename{config.h}.
You will have to uncomment the field named \code{\#define DATE\_TIME\_SUPPORT},
in order to activate date/time support.
Furthermore you will have to provide the library with date and time information.
A set of defines was used for this, when date/time support is not enabled,
the defines automatically return \code{0x0000} for all time and date fields,
so there is no performance suffer when you do not need date/time support.
If you do need it you will have to provide 6 functions to the library
that will tell it the time. Since these functions may get called often,
it is highly recommended that you cache the time result somewhere so
you can serve the library directly from ram. If you do not do this and
your RTC request take a lot of time, you may suffer large losses in read
or write operations depending on your hardware.
The six functions are:
\begin{itemize}
\item\code{euint16 efsl\_getYear(void)}
\item\code{euint8 efsl\_getMonth(void)}
\item\code{euint8 efsl\_getDay(void)}
\item\code{euint8 efsl\_getHour(void)}
\item\code{euint8 efsl\_getMinute(void)}
\item\code{euint8 efsl\_getSecond(void)}
\end{itemize}
Internally the library will recalculate these numbers to match the
filesystem that is currently in use.

View File

@@ -1,38 +0,0 @@
Since debugging on every device is completely different, a DBG macro is
implemented. On Linux for example, this macro will print the string given
to the screen (using printf). On AVR, it will send debug strings through the
UART. For compatibility with other devices, it is necessary that you always use
the DBG-macro instead of a device-specific debugging commands.\newline
\newline
Because AVR-GCC puts strings in sram memory by default, every string should be
surrounded by the TXT-macro. On AVR, this macro will put the string in program
memory (flash), on any other device, this macro will be ignored.\newline
\newline
Example of a debug string:\\
\code{DBG((TXT("This is test nr \%d of \%d.$\backslash$n"),id,total));}
\subsubsection{Debugging on Linux}
On linux, debugging strings are sent to stdout using printf.\newline
\newline
To enable debugging, set DEBUG in \filename{config.h}.
\subsubsection{Debugging on AVR}
On AVR, debugging strings are sent through the UART and can be read using
a terminal like minicom (linux) or hyperterminal (windows). Standard, the
first UART is used, but this can be changed in \filename{debug.c} to the
second UART.\newline
\newline
To enable debugging:
\begin{itemize}
\item{Set DEBUG in \filename{config.h}}
\item{Set CLK to the clock speed of your AVR in \filename{config.h}}
\item{Set BAUDRATE to the baudrate you want in \filename{config.h}}
\item{Initialize debugging in your program by calling \code{debug\_init()}}
\end{itemize}
Remark: when you use the serial port in your main program, make sure you
use a different UART than the one efsl is using when sending debug string.
\subsubsection{Debugging on DSP}
On DSP, debugging strings are sent to Code Composer using the printf function.
\newline\newline
To enable debugging, set DEBUG in \filename{config.h}.\newline
\newline
Remark: this will only work when using a DSK-kit.

View File

@@ -1,166 +0,0 @@
\label{hwdriver}
This section will describe step by step how to write an hardware endpoint.
You will be required to write your own endpoint in case non of the existing endpoints
matches your hardware.
First let's have a look at how EFSL is structured internally.\\\\
\includegraphics[scale=0.4]{schematics/objectmodel.eps}\\
As you can see we have created a linear object model that is quite simple.
The file en filesystem object deal with handling the filesystem specific stuff.
Below that we find the Partition object that is responsible for translating partition
relative addressing into disc-based LBA addressing.
The Disc object hold the partition table, and has a direct link to a cache manager, IOMan.
In IOMan, all requests for disc sectors come together. IOMan will perform checks to see
if sectors have to be read from disc (or from memory), or written back to disc.
In the latter case (reading or writing to disc), a request is made to the hardware layer.
The hardware interface has 3 responsibilities :
\begin{itemize}
\item Initialize the hardware
\item Read sectors from disc
\item Write sectors to disc
\end{itemize}
All requests are \textsl{sector}based, a sector is a 512 byte piece from the disc, that is aligned to
a 512 byte boundary.\\\\
\includegraphics[scale=0.4]{schematics/sector.eps}
In this example we will create a new endpoint that will add support for data over pigeon carrier
for the EFSL. Initializing the hardware will require feeding the pigeon and telling it where the
data is. Reading/Writing will entail giving the bird the sector and letting it fly.
Perform the following steps:
\begin{enumerate}
\item Choose a name for your endpoint\\
You will need this name to create the required defines in the source code.
For our example I've chosen the name \code{PIGEON\_CARRIER}.
For consistency the final name is then \code{HW\_ENDPOINT\_PIGEON\_CARRIER}.
\item Verify the sizes of integers\\
Open \filename{inc/types.h} and create a new entry for pigeon carriers. Perhaps
one of the existing sets is identical to yours and you can copy-paste it.
\item Add your endpoint to \filename{interface.h}\\
Locate the file \filename{interface.h} located in the directory \filename{inc/}
Add a pigeon entry (located above the \code{\#else ... NO INTERFACE DEFINED})
\begin{lstlisting}
#if defined(HW_ENDPOINT_0)
#include "interfaces/0.h"
#elif defined(HW_ENDPOINT_1)
#include "interfaces/1.h"
#elif defined(HW_ENDPOINT_PIGEON_CARRIER)
#include "interfaces/pigeon.h"
#else
#error "NO INTERFACE DEFINED - see interface.h"
#endif
\end{lstlisting}
\item Select your endpoint in \filename{conf/config.h}
\item Create your sourcefiles\\
Create a header file in \filename{inc/} and a sourcefile in \filename {src/interfaces}.
In this example I'm using \filename{pigeon.h} and \filename{pigeon.c}.
\item Add your object file to the Makefile
Take the Makefile that works best on your platform (they should all work with
GNU/Make), or create a new one, using the existing one's as a template.
Make sure to include your new pigeon object to the library.
If you have an 'ar' like utility you can create a static library, else you may
have to create a new project containing all required source files.
\end{enumerate}
The basic framework is now complete, now all that's left to do is to write the code
that will perform the actual flying work.
\subsubsection{hwInterface}
This structure represents the underlying hardware. There are some field that are required
to be present (because EFSL uses them), but you may put in as much or a little as
your driver requires to access the hardware.
As always in embedded design it is recommended to keep this structure as small
as possible.
Example:
\begin{lstlisting}
struct hwInterface{
/* Field created for THIS hardware */
Pigeon pigeon;
/* Obligatory fields */
euint32 sectorCount;
};
typedef struct hwInterface hwInterface;
\end{lstlisting}
\subsubsection{if\_initInterface}
This function will be called one time, when the hardware object is initialized
by \code{efs\_init()}. This code should bring the hardware in a ready to use
state.
The function's prototype is\\
\code{esint16 if\_initInterface(hwInterface *hw, euint8* opts);}
Optionally but recommended you should fill in the hw->sectorCount field with the number
of sectors. This field is used to validate sectorrequests.
An example of a initInterface function :
\begin{lstlisting}
esint16 if_initInterface(hwInterface *hw, euint8* opts)
{
/* Parse options */
parse_options(opts); /* Your application may not need options */
/* Check hardware state */
if(!alive(hw->pigeon)){
//printf("Pigeon died! :-(\n");
return(DEAD_PIGEON); /* #define DEAD_PIGEON -1 */
}
/* Initialize hardware */
feed(hw->pigeon);
pet (hw->pigeon);
/* Get sectors count */
hw->numSectors = ask_pigeon_num_sectors(hw->pigeon);
return(0);
}
\end{lstlisting}
\subsubsection{if\_readBuf}
This function is responsible to read a sector from the disc and store it in a user supplied buffer. You will receive the hardware object, an address and a pointer to memory for storing
the buffer.
Please be very careful to respect the boundaries of the buffers, since it will usually be IOMan
calling this function, and if you have a buffer overflow you might corrupt the cache of the
the next buffer, which in turn may produce extremely rare and impossible to retrace behavior.
The function prototype is:\\
\code{esint16 if\_readBuf(hwInterface *hw,euint32 address, euint8* buf);}
The address is an LBA address, relative to the beginning of the disc. Should you be
accessing an old hard disc, or a device which uses some other form of addressing you will have to
recalculate the address to your own addressing scheme. Please note that there is no support
for sectors that are not 512 bytes large.
\begin{lstlisting}
esint8 if_readBuf(hwInterface* hw,euint32 address,euint8* buf)
{
Message new_message;
new_message.address = address;
new_message.command = READ;
pigeon_send(hw->pigeon,new_message); /* Launches the pigeon */
while(!pigeon_returned(hw->pigeon)); /* Wait until the bird is back */
memcpy(new_message.data,buf,512); /* Copy buffer */
return(0);
}
\end{lstlisting}
\subsubsection{if\_writeBuf}
The function \code{if\_writeBuf} works exactly the same as it's reading variant.

View File

@@ -1,45 +0,0 @@
\subsubsection*{Purpose}
Initializes the hardware and the software layer.
\subsubsection*{Prototype}
\code{esint8 efs\_init(EmbeddedFileSystem *efs, eint8* opts);}
\subsubsection*{Arguments}
Objects passed to \code{efs\_init}:
\begin{itemize}
\item{\code{efs}: empty EmbeddedFileSystem object}
\item
{
\code{opts}: character string containing options, depending on what
interface you are using:
\begin{itemize}
\item{Linux: opts points to the path to the device}
\item{AVR: opts points to the card enable pin (TODO)}
\item{DSP: opts points to the card enable memory address (TODO)}
\end{itemize}
}
\end{itemize}
\subsubsection*{Return value}
Returns 0 if no errors are detected.\\
\newline
Returns non-zero if a low-level error is detected:
\begin{itemize}
\item{Returns -1 if the interface could not be initialized.}
\item{Returns -2 if the filesystem could not be initialized.}
\end{itemize}
\subsubsection*{Example}
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include "efs.h"
void main(void)
{
EmbeddedFileSystem efsl;
esint8 ret;
DBG((TXT("Will init efsl now.\n")));
ret=efs_init(&efsl,"/dev/sda");
if(ret==0)
DBG((TXT("Filesystem correctly initialized.\n")));
else
DBG((TXT("Could not initialize filesystem (err \%d).\n"),ret));
}
\end{lstlisting}

View File

@@ -1,43 +0,0 @@
\subsubsection*{Purpose}
Updates file records and closes file object.
\subsubsection*{Prototype}
\code{esint8 file\_fclose(File *file);}
\subsubsection*{Arguments}
Objects passed to \code{file\_fopen}:
\begin{itemize}
\item{\code{file}: pointer to a File object}
\end{itemize}
\subsubsection*{Return value}
Returns 0 if no errors are detected.\\
\newline
Returns non-zero if an error is detected.
\subsubsection*{Example}
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include "efs.h"
void main(void)
{
EmbeddedFileSystem efsl;
File file;
/* Initialize efsl */
DBG((TXT("Will init efsl now.\n")));
if(efs_init(&efsl,"/dev/sda")!=0){
DBG((TXT("Could not initialize filesystem (err \%d).\n"),ret));
exit(-1);
}
DBG((TXT("Filesystem correctly initialized.\n")));
/* Open file for reading */
if(file_fopen(&file, &efsl.myFs, "read.txt", 'r')!=0){
DBG((TXT("Could not open file for reading.\n")));
exit(-1);
}
DBG((TXT("File opened for reading.\n")));
/* Close file & filesystem */
fclose(&file);
fs_umount(&efs.myFs);
}
\end{lstlisting}

View File

@@ -1,70 +0,0 @@
\subsubsection*{Purpose}
Searches for file and initializes the file object.
\subsubsection*{Prototype}
\code{esint8 file\_fopen(File *file, FileSystem *fs, eint8 *filename, eint8 mode);}
\subsubsection*{Arguments}
Objects passed to \code{file\_fopen}:
\begin{itemize}
\item{\code{file}: pointer to a File object}
\item{\code{fs}: pointer to the FileSystem object}
\item{\code{filename}: pointer to the path + filename}
\item
{
\code{mode}: mode of opening, this can be:
\begin{itemize}
\item{'r': open file for reading}
\item{'w': open file for writing}
\item{'a': open file for appending}
\end{itemize}
}
\end{itemize}
\subsubsection*{Return value}
Returns 0 if no errors are detected.\\
\newline
Returns non-zero if an error is detected:
\begin{itemize}
\item{Returns -1 if the file you are trying to open for reading could not
be found.}
\item{Returns -2 if the file you are trying to open for writing already
exists.}
\item{Returns -3 if no free spot could be found for writing or appending.}
\item{Returns -4 if mode is not correct (if it is not 'r', 'w' or 'a').}
\end{itemize}
\subsubsection*{Example}
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include "efs.h"
void main(void)
{
EmbeddedFileSystem efsl;
File file_read, file_write;
/* Initialize efsl */
DBG((TXT("Will init efsl now.\n")));
if(efs_init(&efsl,"/dev/sda")!=0){
DBG((TXT("Could not initialize filesystem (err \%d).\n"),ret));
exit(-1);
}
DBG((TXT("Filesystem correctly initialized.\n")));
/* Open file for reading */
if(file_fopen(&file_read, &efsl.myFs, "read.txt", 'r')!=0){
DBG((TXT("Could not open file for reading.\n")));
exit(-1);
}
DBG((TXT("File opened for reading.\n")));
/* Open file for writing */
if(file_fopen(&file_write, &efsl.myFs, "write.txt", 'w')!=0){
DBG((TXT("Could not open file for writing.\n")));
exit(-2);
}
DBG((TXT("File opened for writing.\n")));
/* Close files & filesystem */
fclose(&file_read);
fclose(&file_write);
fs_umount(&efs.myFs);
}
\end{lstlisting}

View File

@@ -1,51 +0,0 @@
\subsubsection*{Purpose}
Reads a file and puts it's content in a buffer.
\subsubsection*{Prototype}
\code{euint32 file\_read (File *file, euint32 size, euint8 *buf);}
\subsubsection*{Arguments}
Objects passed to \code{file\_read}:
\begin{itemize}
\item{\code{file}: pointer to a File object}
\item{\code{size}: amount of bytes you want to read / put in buf}
\item{\code{buf}: pointer to the buffer you want to store the data}
\end{itemize}
\subsubsection*{Return value}
Returns the amount of bytes read.
\subsubsection*{Example}
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include "efs.h"
void main(void)
{
EmbeddedFileSystem efsl;
euint8 buffer[512];
euint16 e, f;
File file;
/* Initialize efsl */
DBG((TXT("Will init efsl now.\n")));
if(efs_init(&efsl,"/dev/sda")!=0){
DBG((TXT("Could not initialize filesystem (err \%d).\n"),ret));
exit(-1);
}
DBG((TXT("Filesystem correctly initialized.\n")));
/* Open file for reading */
if(file_fopen(&file, &efsl.myFs, "read.txt", 'r')!=0){
DBG((TXT("Could not open file for reading.\n")));
exit(-1);
}
DBG((TXT("File opened for reading.\n")));
/* Read file and print content */
while((e=file_read(&file,512,buffer))){
for(f=0;f<e;f++)
DBG((TXT("\%c"),buffer[f]));
}
/* Close file & filesystem */
fclose(&file);
fs_umount(&efs.myFs);
}
\end{lstlisting}

View File

@@ -1,52 +0,0 @@
\subsubsection*{Purpose}
Reads a file and puts it's content in a buffer.
\subsubsection*{Prototype}
\code{euint32 file\_write(File *file, euint32 size, euint8 *buf)}
\subsubsection*{Arguments}
Objects passed to \code{file\_read}:
\begin{itemize}
\item{\code{file}: pointer to a File object}
\item{\code{size}: amount of bytes you want to write}
\item{\code{buf}: pointer to the buffer you want to write the data from}
\end{itemize}
\subsubsection*{Return value}
Returns the amount of bytes written.
\subsubsection*{Example}
\lstset{numbers=left, stepnumber=1, numberstyle=\small, numbersep=5pt, tabsize=4}
\begin{lstlisting}
#include <string.h>
#include "efs.h"
void main(void)
{
EmbeddedFileSystem efsl;
euint8 *buffer = "This is a test.\n";
euint16 e=0;
File file;
/* Initialize efsl */
DBG((TXT("Will init efsl now.\n")));
if(efs_init(&efsl,"/dev/sda")!=0){
DBG((TXT("Could not initialize filesystem (err \%d).\n"),ret));
exit(-1);
}
DBG((TXT("Filesystem correctly initialized.\n")));
/* Open file for writing */
if(file_fopen(&file, &efsl.myFs, "write.txt", 'w')!=0){
DBG((TXT("Could not open file for writing.\n")));
exit(-1);
}
DBG((TXT("File opened for reading.\n")));
/* Write buffer to file */
if( file_write(&file,strlen(buffer),buffer) == strlen(buffer) )
DBG((TXT("File written.\n")));
else
DBG((TXT("Could not write file.\n")));
/* Close file & filesystem */
fclose(&file);
fs_umount(&efs.myFs);
}
\end{lstlisting}

View File

@@ -1,236 +0,0 @@
\label{ioman}
The IOManager that is the second lowest layer of the embedded filesystems library is
responsible for coordinating disk input and output, as well as managing a caching
system. This documentation describes the second implementation of IOMan, which includes
features such as :
\begin{itemize}
\item Delayed write
\item Buffer reference statistics
\item Buffer exportable to users
\item Support for cached direct I/O as well as indirect I/O
\item Can allocate memory itself (on the stack), or you can do it yourself (heap)
\end{itemize}
\subsubsection{General operation}
Because of the limited memory nature of most embedded devices for which this library is
intended several design decisions were made to minimize memory usage. Some of these required
that some concessions be made. One of them is that there is no memory protection, since
most devices don't have the memory to support this, or lack the ability to protect memory.
When IOMan receives a request for a sector, it will make sure it has the sector in it's
own memory cache and then give the caller a \code{euint8*} pointer to that cache. The
user is then free to do operations on that memory, and when it is done it should tell
IOMan so. Several things can go wrong with this: you can request a sector for reading,
and then write in the cache, thereby corrupting it. Or you can request a sector, but never
release it (sort of a memory leak), which may result in very bad performance, and a deadlocked
I/O manager.
But, taking into account that very little memory is required for operation, if you follow the I/O man rules, you will get a pretty clever caching object that will make writing new filesystems
a simple job.
\subsubsection{Cache decisions}
Whenever ioman receives a request to fetch a sector, be it read or write, it will have to make sure
it has, or can get the sector you want. It follows a certain path to do this.\label{cachemethod}
\begin{enumerate}
\item First of all it will scan it's cache range to see if it already has the sector.
If it is found, and it was a write request, the cache is marked writable. Usage and
reference get incremented and a pointer is then returned to the requester. If the
buffer cannot be found, ioman proceeds to step 2.
\item When an item is not in cache, it has to be fetched from the disc, the best place to
store it is in memory that does not contain anything useful yet. Ioman will search for
a place that is currently not occupied by anything. If it is found, the sector will be
placed on that spot and a pointer returned. Else, ioman proceeds to step 3.
\item Since there is no other choice than to overwrite an already existing cache, ioman will
try to find one that is the least interesting. First it will search for caches that
are marked not writable, and have no users. Ioman will then select the one that has the
least references. If there are none, it will search for caches that don't have users and
are writable. Once again the one with the least references is returned. Since it is
writable ioman will flush it to disc first. After that the requested sector is put there
and a pointer returned. If it cannot find any caches that have no users it will go to
step 4.
\item Since every cache spot is in use ioman will have to select one for overallocation.
Since this selection depends on many factors and is rather complex, a points
system is used. The algorithm considers every cache place and allocated a certain number
of points to it, lower means that it is a better candidate for overallocation. Fifty
percent of the points goes to the cache being marked writable, since having to write
a sector is expensive. Another 35 percent goes to how many overallocations have
already been done on that spot. It doesn't make sense to always overalloc the same buffer,
it is better to spread this. The remaining 15 percent is determined by the number of
references to the sector.
After a function has selected the best candidate, ioman will overwrite that spot with
the new sector. It will also push the status and sectornumber onto that cache's
retrieval stack, so that when the sector is released, the older sector can be retrieved.
If this fails go to step 5.
\item When ioman gets here it will return a (nil) pointer and flag an error.
\end{enumerate}
\subsubsection{Functions}
\begin{longtable}{|p{0.35\textwidth}|p{0.65\textwidth}|}
\hline
\multicolumn{2}{|c|}{
\textbf{I/O Manager Functions}
} \\
\multicolumn{2}{|c|}{} \\
\hline
\hline
\endfirsthead
\hline
\multicolumn{2}{|c|}{\textbf{I/O Manager Functions (continued)}} \\
\hline
\endhead
\hline
\endfoot
\hline
\endlastfoot
\code{ioman\_init} & \code{esint8 (IOManager *ioman, hwInterface *iface, euint8* bufferarea)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function is called to initialize the internal state of the I/O manager. It should be the
first function you call on an ioman object. Failure to do so will result in undefined behavior.
The function clears all internal variables to a default safe state, and sets up it's memory region.
There are two possibilities, if you supply a 0 pointer then a function will be called that contains
a static variable with a size of 512 * \code{IOMAN\_NUMBUFFERS}, else, it will be assumed that
you allocated that memory yourself and the pointer you provided will be used.
}\\
\hline
\code{\external{ioman\_reset}} & \code{void (IOManager *ioman)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function is called from the initialization function, it does the actual reset of all variables.
}\\
\hline
\code{ioman\_pop} & \code{esint8 (IOManager *ioman,euint16 bufplace)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function fetches settings (sector number, usage and status register) from stack \code{bufplace}
and puts it back on the main registers. It will return 0 on successful pop, and -1 on error, or when
there are no elements to pop.
}\\
\hline
\code{ioman\_push} & \code{esint8 (IOManager *ioman,euint16 bufplace)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function pushes the settings of cache \code{bufplace} onto that cache's stack. It does not
destroy the data in the main registers. It will return 0 for a successful push, and -1 on error, or
when there is no more space to push a new element.
}\\
\hline
\code{ioman\_readSector} & \code{esint8 (IOManager *ioman,euint32 address,euint8* buf)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function does the actual reading from the hardware, it is the one and only function that
calls \code{if\_readBuf()}, here a retry on failure policy could be implemented. This function
will correctly stream errors upwards. All calls made to this function in the iomanager are checked
for their return value, so errors propagate correctly upwards.
The address it receives is relative to the beginning of the disc, no assumptions about \code{buf}
may be made, it can be withing ioman's cache memory range, but it could also be a buffer from userspace.
The function will return 0 on success and -1 on failure.
}\\
\hline
\code{ioman\_writeSector} & \code{esint8 (IOManager *ioman, euint32 address, euint8* buf)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function does the actual writing to the hardware, it is the one and only function that
calls \code{if\_writeBuf()}, here a retry on failure policy could be implemented. This function
will correctly stream errors upwards. All calls made to this function in the iomanager are checked
for their return value, so errors propagate correctly upwards.
The address it receives is relative to the beginning of the disc, no assumptions about \code{buf}
may be made, it can be withing ioman's cache memory range, but it could also be a buffer from userspace.
The function will return 0 on success and -1 on failure.
}\\
\hline
\code{\external{ioman\_getSector}} & \code{euint8* (IOManager *ioman,euint32 address, euint8 mode)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function is the one that is called most from the higher library routines. It is the function
that will present you with a pointer to memory containing sector number \code{address}. There are
several modes that you can select or combine.\newline
\begin{tabular}{|l|p{.6\textwidth}|}
\hline
\code{IOM\_MODE\_READONLY} & This attribute says to ioman that it needs a buffer only for reading.
This does not mean that you are allowed to write to it, doing so results in undefined behavior.
You cannot combine this option with the \code{IOM\_MODE\_READWRITE} option.\\
\code{IOM\_MODE\_READWRITE} & This attribute says to ioman that it would like not only to read from
but also to write to that buffer. When you release the sector your changes will be written to disc.
This may not happen immediately though, if you want to force it take a look at the
\code{ioman\_flushRange()} function. This option cannot be combined with the
\code{IOM\_MODE\_READONLY} option.\\
\code{IOM\_MODE\_EXP\_REQ} & This option tell the iomanager that the request is exceptional, for
example that the request is unlikely to happen again. The library adds this flags to the options
when requesting the bootrecord, to prevent it from getting a high rating, which should prevent it
from being removed from the cache.\\
\hline
\end{tabular}\newline
These options can be combined by ORing them together.
}\\
\hline
\code{ioman\_releaseSector} & \code{esint8 (IOManager *ioman,euint8* buf)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function tells ioman that you are done with one of the cache elements and that it can do
it's bidding with it. Forgetting to call this function may result in deadlocked iomanagers.
}\\
\hline
\code{ioman\_directSectorRead} & \code{esint8 (IOManager *ioman,euint32 address, euint8* buf)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This is a variant of the normal getsector. Sometimes you need a sector from the disc, but all
you want to do with it is export it directly to userbuffers. It would be foolish to force a
caching of that sector if there is external space available for it.
This function will fetch sector \code{address} from disc and place it in the memory pointed to
by \code{buf}. Should there be a free spot available the sector will be cached there, so that
it may be used in the future. If the sector was available from cache in the first place, it
will simply be \code{memCpy()}'d from the cache to the userspace buffer.
}\\
\hline
\code{ioman\_directSectorWrite} & \code{esint8 (IOManager *ioman,euint32 address, euint8* buf)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function is based on the same philosophy as \code{ioman\_directSectorRead()}, however,
contrary to what the name may lead to believe it also passes through a caching layer. If
there is an unused spot (or the sector is in cache), the userbuffer will be copied to that
spot and will remain there until the space is needed or a flush is forced.
}\\
\hline
\code{ioman\_flushRange} & \code{esint8 (IOManager *ioman,euint32 address\_low, euint32 address\_high)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function is used to ask ioman to flush all sectors to disc that are in a specific
range. For example you might want to flush a specific range of your filesystem without
needlessly disturb other parts. The range is \code{address\_low <= n => address\_high}.
Off course only sectors that are marked as writable are flushed to disc.
}\\
\hline
\code{ioman\_flushAll} & \code{esint8 (IOManager *ioman)} \\
\hline
\multicolumn{2}{|p{\textwidth}|}{
This function will cause ioman to flush out all cache units that are marked writable. If
they do not have any users, they will lose their writable mark.
}\\
\hline
\end{longtable}

View File

@@ -1,489 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

View File

@@ -1,12 +0,0 @@
This library is subject to the Lesser General Public License version 2.1.
We have chosen this license in stead of the BSD license because we feel strongly
that more effort was needed in the field of quality software in the embedded field.
Please note that if you make changes to the library itself, those modifications must be
made public, but that writing support for new hardware and linking it into the library,
does not fall under this category. However, we would off course appreciate it tremendously
if you would send us in code to support new hardware.
\subsection{GNU Lesser General Public License}
\verbatiminput{pages/lgpl.txt}

Some files were not shown because too many files have changed in this diff Show More