Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea792090e3 |
@@ -33,7 +33,7 @@ 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 \
|
||||||
command.o mmc.o fat.o file.o dir.o testing.o
|
command.o testing.o rtc.o mmc.o ff.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
|
||||||
|
|||||||
@@ -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_FAT 32
|
#define DEBUG_SREG 32
|
||||||
#define DEBUG_CRC 64
|
#define DEBUG_CRC 64
|
||||||
#define DEBUG_SHM 128
|
#define DEBUG_SHM 128
|
||||||
|
|
||||||
|
|||||||
@@ -1,96 +0,0 @@
|
|||||||
/*
|
|
||||||
* =====================================================================================
|
|
||||||
*
|
|
||||||
* ________ .__ __ ________ ____ ________
|
|
||||||
* \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
|
|
||||||
* / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
|
|
||||||
* / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
|
|
||||||
* \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
|
|
||||||
* \__> \/ \/ \/ \/ \/
|
|
||||||
*
|
|
||||||
* 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();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
/*
|
|
||||||
* =====================================================================================
|
|
||||||
*
|
|
||||||
* ________ .__ __ ________ ____ ________
|
|
||||||
* \_____ \ __ __|__| ____ | | __\______ \ _______ _/_ |/ _____/
|
|
||||||
* / / \ \| | \ |/ ___\| |/ / | | \_/ __ \ \/ /| / __ \
|
|
||||||
* / \_/. \ | / \ \___| < | ` \ ___/\ / | \ |__\ \
|
|
||||||
* \_____\ \_/____/|__|\___ >__|_ \/_______ /\___ >\_/ |___|\_____ /
|
|
||||||
* \__> \/ \/ \/ \/ \/
|
|
||||||
*
|
|
||||||
* www.optixx.org
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Version: 1.0
|
|
||||||
* Created: 07/21/2009 03:32:16 PM
|
|
||||||
* Author: david@optixx.org
|
|
||||||
*
|
|
||||||
* =====================================================================================
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __DIR_H__
|
|
||||||
#define __DIR_H__
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdint.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
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
uint32_t id; // 4
|
|
||||||
uint8_t file_name[13]; // 8.3 = 12 + 1 = 13
|
|
||||||
uint32_t file_size; // 4
|
|
||||||
uint8_t file_attr; // 1
|
|
||||||
uint8_t snes_header[41]; // 41
|
|
||||||
} dir_ent_t; // 64
|
|
||||||
|
|
||||||
void dir_entry_start();
|
|
||||||
void dir_entry_add(uint32_t id, uint8_t* file_name,uint32_t file_size,uint8_t file_attr);
|
|
||||||
void dir_entry_header(uint16_t position, uint8_t * header);
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
lo:
|
|
||||||
0x7fc0
|
|
||||||
0x7fc0 + 0x200
|
|
||||||
|
|
||||||
hi:
|
|
||||||
0xffc0
|
|
||||||
0xffc0 + 0x200
|
|
||||||
|
|
||||||
emulated reset vector MSB must be set
|
|
||||||
|
|
||||||
sei
|
|
||||||
clc
|
|
||||||
xce
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#endif
|
|
||||||
81
avr/usbload/diskio.h
Normal file
81
avr/usbload/diskio.h
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*-----------------------------------------------------------------------
|
||||||
|
/ Low level disk interface modlue include file R0.05 (C)ChaN, 2007
|
||||||
|
/-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _DISKIO
|
||||||
|
|
||||||
|
#define _READONLY 0 /* 1: Read-only mode */
|
||||||
|
#define _USE_IOCTL 1
|
||||||
|
|
||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* Status of Disk Functions */
|
||||||
|
typedef BYTE DSTATUS;
|
||||||
|
|
||||||
|
/* Results of Disk Functions */
|
||||||
|
typedef enum {
|
||||||
|
RES_OK = 0, /* 0: Successful */
|
||||||
|
RES_ERROR, /* 1: R/W Error */
|
||||||
|
RES_WRPRT, /* 2: Write Protected */
|
||||||
|
RES_NOTRDY, /* 3: Not Ready */
|
||||||
|
RES_PARERR /* 4: Invalid Parameter */
|
||||||
|
} DRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
/*---------------------------------------*/
|
||||||
|
/* Prototypes for disk control functions */
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (BYTE);
|
||||||
|
DSTATUS disk_status (BYTE);
|
||||||
|
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
|
||||||
|
#if _READONLY == 0
|
||||||
|
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
|
||||||
|
#endif
|
||||||
|
DRESULT disk_ioctl (BYTE, BYTE, void*);
|
||||||
|
void disk_timerproc (void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Disk Status Bits (DSTATUS) */
|
||||||
|
|
||||||
|
#define STA_NOINIT 0x01 /* Drive not initialized */
|
||||||
|
#define STA_NODISK 0x02 /* No medium in the drive */
|
||||||
|
#define STA_PROTECT 0x04 /* Write protected */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Command code for disk_ioctrl() */
|
||||||
|
|
||||||
|
/* Generic command */
|
||||||
|
#define CTRL_SYNC 0 /* Mandatory for write functions */
|
||||||
|
#define GET_SECTOR_COUNT 1 /* Mandatory for only f_mkfs() */
|
||||||
|
#define GET_SECTOR_SIZE 2
|
||||||
|
#define GET_BLOCK_SIZE 3 /* Mandatory for only f_mkfs() */
|
||||||
|
#define CTRL_POWER 4
|
||||||
|
#define CTRL_LOCK 5
|
||||||
|
#define CTRL_EJECT 6
|
||||||
|
/* MMC/SDC command */
|
||||||
|
#define MMC_GET_TYPE 10
|
||||||
|
#define MMC_GET_CSD 11
|
||||||
|
#define MMC_GET_CID 12
|
||||||
|
#define MMC_GET_OCR 13
|
||||||
|
#define MMC_GET_SDSTAT 14
|
||||||
|
/* ATA/CF command */
|
||||||
|
#define ATA_GET_REV 20
|
||||||
|
#define ATA_GET_MODEL 21
|
||||||
|
#define ATA_GET_SN 22
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Card type flags (CardType) */
|
||||||
|
#define CT_MMC 0x01
|
||||||
|
#define CT_SD1 0x02
|
||||||
|
#define CT_SD2 0x04
|
||||||
|
#define CT_SDC (CT_SD1|CT_SD2)
|
||||||
|
#define CT_BLOCK 0x08
|
||||||
|
|
||||||
|
|
||||||
|
#define _DISKIO
|
||||||
|
#endif
|
||||||
@@ -1,668 +0,0 @@
|
|||||||
|
|
||||||
#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
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
|
|
||||||
#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
|
|
||||||
2936
avr/usbload/ff.c
Normal file
2936
avr/usbload/ff.c
Normal file
File diff suppressed because it is too large
Load Diff
547
avr/usbload/ff.h
Normal file
547
avr/usbload/ff.h
Normal file
@@ -0,0 +1,547 @@
|
|||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ FatFs - FAT file system module include file R0.07a (C)ChaN, 2009
|
||||||
|
/----------------------------------------------------------------------------/
|
||||||
|
/ FatFs module is an open source software to implement FAT file system to
|
||||||
|
/ small embedded systems. This is a free software and is opened for education,
|
||||||
|
/ research and commercial developments under license policy of following trems.
|
||||||
|
/
|
||||||
|
/ Copyright (C) 2009, ChaN, all right reserved.
|
||||||
|
/
|
||||||
|
/ * The FatFs module is a free software and there is NO WARRANTY.
|
||||||
|
/ * No restriction on use. You can use, modify and redistribute it for
|
||||||
|
/ personal, non-profit or commercial use UNDER YOUR RESPONSIBILITY.
|
||||||
|
/ * Redistributions of source code must retain the above copyright notice.
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
/*---------------------------------------------------------------------------/
|
||||||
|
/ FatFs Configuration Options
|
||||||
|
/
|
||||||
|
/ CAUTION! Do not forget to make clean the project after any changes to
|
||||||
|
/ the configuration options.
|
||||||
|
/
|
||||||
|
/----------------------------------------------------------------------------*/
|
||||||
|
#ifndef _FATFS
|
||||||
|
#define _FATFS
|
||||||
|
|
||||||
|
#define _WORD_ACCESS 1
|
||||||
|
/* The _WORD_ACCESS option defines which access method is used to the word
|
||||||
|
/ data in the FAT structure.
|
||||||
|
/
|
||||||
|
/ 0: Byte-by-byte access. Always compatible with all platforms.
|
||||||
|
/ 1: Word access. Do not choose this unless following condition is met.
|
||||||
|
/
|
||||||
|
/ When the byte order on the memory is big-endian or address miss-aligned
|
||||||
|
/ word access results incorrect behavior, the _WORD_ACCESS must be set to 0.
|
||||||
|
/ If it is not the case, the value can also be set to 1 to improve the
|
||||||
|
/ performance and code efficiency. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_READONLY 0
|
||||||
|
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
|
||||||
|
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
|
||||||
|
/ f_truncate and useless f_getfree. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_MINIMIZE 0
|
||||||
|
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
|
||||||
|
/
|
||||||
|
/ 0: Full function.
|
||||||
|
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
|
||||||
|
/ are removed.
|
||||||
|
/ 2: f_opendir and f_readdir are removed in addition to level 1.
|
||||||
|
/ 3: f_lseek is removed in addition to level 2. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_TINY 1
|
||||||
|
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
|
||||||
|
/ object instead of the sector buffer in the individual file object for file
|
||||||
|
/ data transfer. This reduces memory consumption 512 bytes each file object. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_STRFUNC 0
|
||||||
|
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_MKFS 1
|
||||||
|
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_FORWARD 0
|
||||||
|
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _DRIVES 2
|
||||||
|
/* Number of volumes (logical drives) to be used. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _MAX_SS 512
|
||||||
|
/* Maximum sector size to be handled. (512/1024/2048/4096) */
|
||||||
|
/* 512 for memroy card and hard disk, 1024 for floppy disk, 2048 for MO disk */
|
||||||
|
|
||||||
|
|
||||||
|
#define _MULTI_PARTITION 0
|
||||||
|
/* When _MULTI_PARTITION is set to 0, each volume is bound to the same physical
|
||||||
|
/ drive number and can mount only first primaly partition. When it is set to 1,
|
||||||
|
/ each volume is tied to the partitions listed in Drives[]. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _CODE_PAGE 437
|
||||||
|
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
|
||||||
|
/ When it is non LFN configuration, there is no difference between SBCS code
|
||||||
|
/ pages. When LFN is enabled, the code page must always be set correctly.
|
||||||
|
/ 437 - U.S.
|
||||||
|
/ 720 - Arabic
|
||||||
|
/ 737 - Greek
|
||||||
|
/ 775 - Baltic
|
||||||
|
/ 850 - Multilingual Latin 1
|
||||||
|
/ 852 - Latin 2
|
||||||
|
/ 855 - Cyrillic
|
||||||
|
/ 857 - Turkish
|
||||||
|
/ 858 - Multilingual Latin 1 + Euro
|
||||||
|
/ 862 - Hebrew
|
||||||
|
/ 866 - Russian
|
||||||
|
/ 874 - Thai
|
||||||
|
/ 932 - Japanese Shift-JIS (DBCS)
|
||||||
|
/ 936 - Simplified Chinese GBK (DBCS)
|
||||||
|
/ 949 - Korean (DBCS)
|
||||||
|
/ 950 - Traditional Chinese Big5 (DBCS)
|
||||||
|
/ 1258 - Vietnam
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define _USE_LFN 0
|
||||||
|
#define _MAX_LFN 255 /* Maximum LFN length to handle (max:255) */
|
||||||
|
/* The _USE_LFN option switches the LFN support.
|
||||||
|
/
|
||||||
|
/ 0: Disable LFN.
|
||||||
|
/ 1: Enable LFN with static working buffer on the bss. NOT REENTRANT.
|
||||||
|
/ 2: Enable LFN with dynamic working buffer on the caller's STACK.
|
||||||
|
/
|
||||||
|
/ The working buffer occupies (_MAX_LFN + 1) * 2 bytes. When enable LFN,
|
||||||
|
/ a Unicode - OEM code conversion function ff_convert() must be added to
|
||||||
|
/ the project. */
|
||||||
|
|
||||||
|
|
||||||
|
#define _FS_REENTRANT 0
|
||||||
|
#define _TIMEOUT 1000 /* Timeout period in unit of time ticks */
|
||||||
|
#define _SYNC_t HANDLE /* Type of sync object used on the OS. */
|
||||||
|
/* e.g. HANDLE, OS_EVENT*, ID and etc.. */
|
||||||
|
/* To make the FatFs module re-entrant, set _FS_REENTRANT to 1 and add user
|
||||||
|
/ provided synchronization handlers, ff_req_grant, ff_rel_grant,
|
||||||
|
/ ff_del_syncobj and ff_cre_syncobj function to the project. */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* End of configuration options. Do not change followings without care. */
|
||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Definitions corresponds to multiple sector size */
|
||||||
|
|
||||||
|
#if _MAX_SS == 512
|
||||||
|
#define SS(fs) 512
|
||||||
|
#else
|
||||||
|
#if _MAX_SS == 1024 || _MAX_SS == 2048 || _MAX_SS == 4096
|
||||||
|
#define SS(fs) ((fs)->s_size)
|
||||||
|
#else
|
||||||
|
#error Sector size must be 512, 1024, 2048 or 4096.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File system object structure */
|
||||||
|
|
||||||
|
typedef struct _FATFS {
|
||||||
|
BYTE fs_type; /* FAT sub type */
|
||||||
|
BYTE drive; /* Physical drive number */
|
||||||
|
BYTE csize; /* Number of sectors per cluster */
|
||||||
|
BYTE n_fats; /* Number of FAT copies */
|
||||||
|
BYTE wflag; /* win[] dirty flag (1:must be written back) */
|
||||||
|
BYTE pad1;
|
||||||
|
WORD id; /* File system mount ID */
|
||||||
|
WORD n_rootdir; /* Number of root directory entries (0 on FAT32) */
|
||||||
|
#if _FS_REENTRANT
|
||||||
|
_SYNC_t sobj; /* Identifier of sync object */
|
||||||
|
#endif
|
||||||
|
#if _MAX_SS != 512U
|
||||||
|
WORD s_size; /* Sector size */
|
||||||
|
#endif
|
||||||
|
#if !_FS_READONLY
|
||||||
|
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
|
||||||
|
BYTE pad2;
|
||||||
|
DWORD last_clust; /* Last allocated cluster */
|
||||||
|
DWORD free_clust; /* Number of free clusters */
|
||||||
|
DWORD fsi_sector; /* fsinfo sector */
|
||||||
|
#endif
|
||||||
|
DWORD sects_fat; /* Sectors per fat */
|
||||||
|
DWORD max_clust; /* Maximum cluster# + 1. Number of clusters is max_clust - 2 */
|
||||||
|
DWORD fatbase; /* FAT start sector */
|
||||||
|
DWORD dirbase; /* Root directory start sector (Cluster# on FAT32) */
|
||||||
|
DWORD database; /* Data start sector */
|
||||||
|
DWORD winsect; /* Current sector appearing in the win[] */
|
||||||
|
BYTE win[_MAX_SS];/* Disk access window for Directory/FAT */
|
||||||
|
} FATFS;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Directory object structure */
|
||||||
|
|
||||||
|
typedef struct _DIR {
|
||||||
|
WORD id; /* Owner file system mount ID */
|
||||||
|
WORD index; /* Current index number */
|
||||||
|
FATFS* fs; /* Pointer to the owner file system object */
|
||||||
|
DWORD sclust; /* Table start cluster (0:Static table) */
|
||||||
|
DWORD clust; /* Current cluster */
|
||||||
|
DWORD sect; /* Current sector */
|
||||||
|
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
|
||||||
|
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
|
||||||
|
#if _USE_LFN
|
||||||
|
WCHAR* lfn; /* Pointer to the LFN working buffer */
|
||||||
|
WORD lfn_idx; /* Last matched LFN index (0xFFFF:No LFN) */
|
||||||
|
#endif
|
||||||
|
} DIR;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File object structure */
|
||||||
|
|
||||||
|
typedef struct _FIL {
|
||||||
|
FATFS* fs; /* Pointer to the owner file system object */
|
||||||
|
WORD id; /* Owner file system mount ID */
|
||||||
|
BYTE flag; /* File status flags */
|
||||||
|
BYTE csect; /* Sector address in the cluster */
|
||||||
|
DWORD fptr; /* File R/W pointer */
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
DWORD org_clust; /* File start cluster */
|
||||||
|
DWORD curr_clust; /* Current cluster */
|
||||||
|
DWORD dsect; /* Current data sector */
|
||||||
|
#if !_FS_READONLY
|
||||||
|
DWORD dir_sect; /* Sector containing the directory entry */
|
||||||
|
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
|
||||||
|
#endif
|
||||||
|
#if !_FS_TINY
|
||||||
|
BYTE buf[_MAX_SS];/* File R/W buffer */
|
||||||
|
#endif
|
||||||
|
} FIL;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File status structure */
|
||||||
|
|
||||||
|
typedef struct _FILINFO {
|
||||||
|
DWORD fsize; /* File size */
|
||||||
|
WORD fdate; /* Last modified date */
|
||||||
|
WORD ftime; /* Last modified time */
|
||||||
|
BYTE fattrib; /* Attribute */
|
||||||
|
char fname[13]; /* Short file name (8.3 format) */
|
||||||
|
#if _USE_LFN
|
||||||
|
char *lfname; /* Pointer to the LFN buffer */
|
||||||
|
int lfsize; /* Size of LFN buffer [bytes] */
|
||||||
|
#endif
|
||||||
|
} FILINFO;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* DBCS code ranges */
|
||||||
|
|
||||||
|
#if _CODE_PAGE == 932 /* CP932 (Japanese Shift-JIS) */
|
||||||
|
#define _DF1S 0x81 /* DBC 1st byte range 1 start */
|
||||||
|
#define _DF1E 0x9F /* DBC 1st byte range 1 end */
|
||||||
|
#define _DF2S 0xE0 /* DBC 1st byte range 2 start */
|
||||||
|
#define _DF2E 0xFC /* DBC 1st byte range 2 end */
|
||||||
|
#define _DS1S 0x40 /* DBC 2nd byte range 1 start */
|
||||||
|
#define _DS1E 0x7E /* DBC 2nd byte range 1 end */
|
||||||
|
#define _DS2S 0x80 /* DBC 2nd byte range 2 start */
|
||||||
|
#define _DS2E 0xFC /* DBC 2nd byte range 2 end */
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 936 /* CP936 (Simplified Chinese GBK) */
|
||||||
|
#define _DF1S 0x81
|
||||||
|
#define _DF1E 0xFE
|
||||||
|
#define _DS1S 0x40
|
||||||
|
#define _DS1E 0x7E
|
||||||
|
#define _DS2S 0x80
|
||||||
|
#define _DS2E 0xFE
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 949 /* CP949 (Korean) */
|
||||||
|
#define _DF1S 0x81
|
||||||
|
#define _DF1E 0xFE
|
||||||
|
#define _DS1S 0x41
|
||||||
|
#define _DS1E 0x5A
|
||||||
|
#define _DS2S 0x61
|
||||||
|
#define _DS2E 0x7A
|
||||||
|
#define _DS3S 0x81
|
||||||
|
#define _DS3E 0xFE
|
||||||
|
|
||||||
|
#elif _CODE_PAGE == 950 /* CP950 (Traditional Chinese Big5) */
|
||||||
|
#define _DF1S 0x81
|
||||||
|
#define _DF1E 0xFE
|
||||||
|
#define _DS1S 0x40
|
||||||
|
#define _DS1E 0x7E
|
||||||
|
#define _DS2S 0xA1
|
||||||
|
#define _DS2E 0xFE
|
||||||
|
|
||||||
|
#else /* SBCS code pages */
|
||||||
|
#define _DF1S 0
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Character code support macros */
|
||||||
|
|
||||||
|
#define IsUpper(c) (((c)>='A')&&((c)<='Z'))
|
||||||
|
#define IsLower(c) (((c)>='a')&&((c)<='z'))
|
||||||
|
#define IsDigit(c) (((c)>='0')&&((c)<='9'))
|
||||||
|
|
||||||
|
#if _DF1S /* DBCS configuration */
|
||||||
|
|
||||||
|
#if _DF2S /* Two 1st byte areas */
|
||||||
|
#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
|
||||||
|
#else /* One 1st byte area */
|
||||||
|
#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if _DS3S /* Three 2nd byte areas */
|
||||||
|
#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
|
||||||
|
#else /* Two 2nd byte areas */
|
||||||
|
#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else /* SBCS configuration */
|
||||||
|
|
||||||
|
#define IsDBCS1(c) 0
|
||||||
|
#define IsDBCS2(c) 0
|
||||||
|
|
||||||
|
#endif /* _DF1S */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Definitions corresponds to multi partition */
|
||||||
|
|
||||||
|
#if _MULTI_PARTITION /* Multiple partition configuration */
|
||||||
|
|
||||||
|
typedef struct _PARTITION {
|
||||||
|
BYTE pd; /* Physical drive# */
|
||||||
|
BYTE pt; /* Partition # (0-3) */
|
||||||
|
} PARTITION;
|
||||||
|
|
||||||
|
extern
|
||||||
|
const PARTITION Drives[]; /* Logical drive# to physical location conversion table */
|
||||||
|
#define LD2PD(drv) (Drives[drv].pd) /* Get physical drive# */
|
||||||
|
#define LD2PT(drv) (Drives[drv].pt) /* Get partition# */
|
||||||
|
|
||||||
|
#else /* Single partition configuration */
|
||||||
|
|
||||||
|
#define LD2PD(drv) (drv) /* Physical drive# is equal to the logical drive# */
|
||||||
|
#define LD2PT(drv) 0 /* Always mounts the 1st partition */
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* File function return code (FRESULT) */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FR_OK = 0, /* 0 */
|
||||||
|
FR_DISK_ERR, /* 1 */
|
||||||
|
FR_INT_ERR, /* 2 */
|
||||||
|
FR_NOT_READY, /* 3 */
|
||||||
|
FR_NO_FILE, /* 4 */
|
||||||
|
FR_NO_PATH, /* 5 */
|
||||||
|
FR_INVALID_NAME, /* 6 */
|
||||||
|
FR_DENIED, /* 7 */
|
||||||
|
FR_EXIST, /* 8 */
|
||||||
|
FR_INVALID_OBJECT, /* 9 */
|
||||||
|
FR_WRITE_PROTECTED, /* 10 */
|
||||||
|
FR_INVALID_DRIVE, /* 11 */
|
||||||
|
FR_NOT_ENABLED, /* 12 */
|
||||||
|
FR_NO_FILESYSTEM, /* 13 */
|
||||||
|
FR_MKFS_ABORTED, /* 14 */
|
||||||
|
FR_TIMEOUT /* 15 */
|
||||||
|
} FRESULT;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* FatFs module application interface */
|
||||||
|
|
||||||
|
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
|
||||||
|
FRESULT f_open (FIL*, const char*, BYTE); /* Open or create a file */
|
||||||
|
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
|
||||||
|
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
|
||||||
|
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
|
||||||
|
FRESULT f_close (FIL*); /* Close an open file object */
|
||||||
|
FRESULT f_opendir (DIR*, const char*); /* Open an existing directory */
|
||||||
|
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
|
||||||
|
FRESULT f_stat (const char*, FILINFO*); /* Get file status */
|
||||||
|
FRESULT f_getfree (const char*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
|
||||||
|
FRESULT f_truncate (FIL*); /* Truncate file */
|
||||||
|
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
|
||||||
|
FRESULT f_unlink (const char*); /* Delete an existing file or directory */
|
||||||
|
FRESULT f_mkdir (const char*); /* Create a new directory */
|
||||||
|
FRESULT f_chmod (const char*, BYTE, BYTE); /* Change attriburte of the file/dir */
|
||||||
|
FRESULT f_utime (const char*, const FILINFO*); /* Change timestamp of the file/dir */
|
||||||
|
FRESULT f_rename (const char*, const char*); /* Rename/Move a file or directory */
|
||||||
|
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
|
||||||
|
FRESULT f_mkfs (BYTE, BYTE, WORD); /* Create a file system on the drive */
|
||||||
|
|
||||||
|
#if _USE_STRFUNC
|
||||||
|
int f_putc (int, FIL*); /* Put a character to the file */
|
||||||
|
int f_puts (const char*, FIL*); /* Put a string to the file */
|
||||||
|
int f_printf (FIL*, const char*, ...); /* Put a formatted string to the file */
|
||||||
|
char* f_gets (char*, int, FIL*); /* Get a string from the file */
|
||||||
|
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
|
||||||
|
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
|
||||||
|
#ifndef EOF
|
||||||
|
#define EOF -1
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* User defined functions */
|
||||||
|
|
||||||
|
/* Real time clock */
|
||||||
|
#if !_FS_READONLY
|
||||||
|
DWORD get_fattime (void); /* 31-25: Year(0-127 org.1980), 24-21: Month(1-12), 20-16: Day(1-31) */
|
||||||
|
/* 15-11: Hour(0-23), 10-5: Minute(0-59), 4-0: Second(0-29 *2) */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Unicode - OEM code conversion */
|
||||||
|
#if _USE_LFN
|
||||||
|
WCHAR ff_convert (WCHAR, UINT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Sync functions */
|
||||||
|
#if _FS_REENTRANT
|
||||||
|
BOOL ff_cre_syncobj(BYTE, _SYNC_t*);
|
||||||
|
BOOL ff_del_syncobj(_SYNC_t);
|
||||||
|
BOOL ff_req_grant(_SYNC_t);
|
||||||
|
void ff_rel_grant(_SYNC_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------*/
|
||||||
|
/* Flags and offset address */
|
||||||
|
|
||||||
|
|
||||||
|
/* File access control and file status flags (FIL.flag) */
|
||||||
|
|
||||||
|
#define FA_READ 0x01
|
||||||
|
#define FA_OPEN_EXISTING 0x00
|
||||||
|
#if _FS_READONLY == 0
|
||||||
|
#define FA_WRITE 0x02
|
||||||
|
#define FA_CREATE_NEW 0x04
|
||||||
|
#define FA_CREATE_ALWAYS 0x08
|
||||||
|
#define FA_OPEN_ALWAYS 0x10
|
||||||
|
#define FA__WRITTEN 0x20
|
||||||
|
#define FA__DIRTY 0x40
|
||||||
|
#endif
|
||||||
|
#define FA__ERROR 0x80
|
||||||
|
|
||||||
|
|
||||||
|
/* FAT sub type (FATFS.fs_type) */
|
||||||
|
|
||||||
|
#define FS_FAT12 1
|
||||||
|
#define FS_FAT16 2
|
||||||
|
#define FS_FAT32 3
|
||||||
|
|
||||||
|
|
||||||
|
/* File attribute bits for directory entry */
|
||||||
|
|
||||||
|
#define AM_RDO 0x01 /* Read only */
|
||||||
|
#define AM_HID 0x02 /* Hidden */
|
||||||
|
#define AM_SYS 0x04 /* System */
|
||||||
|
#define AM_VOL 0x08 /* Volume label */
|
||||||
|
#define AM_LFN 0x0F /* LFN entry */
|
||||||
|
#define AM_DIR 0x10 /* Directory */
|
||||||
|
#define AM_ARC 0x20 /* Archive */
|
||||||
|
#define AM_MASK 0x3F /* Mask of defined bits */
|
||||||
|
|
||||||
|
|
||||||
|
/* FatFs refers the members in the FAT structures with byte offset instead
|
||||||
|
/ of structure member because there are incompatibility of the packing option
|
||||||
|
/ between various compilers. */
|
||||||
|
|
||||||
|
#define BS_jmpBoot 0
|
||||||
|
#define BS_OEMName 3
|
||||||
|
#define BPB_BytsPerSec 11
|
||||||
|
#define BPB_SecPerClus 13
|
||||||
|
#define BPB_RsvdSecCnt 14
|
||||||
|
#define BPB_NumFATs 16
|
||||||
|
#define BPB_RootEntCnt 17
|
||||||
|
#define BPB_TotSec16 19
|
||||||
|
#define BPB_Media 21
|
||||||
|
#define BPB_FATSz16 22
|
||||||
|
#define BPB_SecPerTrk 24
|
||||||
|
#define BPB_NumHeads 26
|
||||||
|
#define BPB_HiddSec 28
|
||||||
|
#define BPB_TotSec32 32
|
||||||
|
#define BS_55AA 510
|
||||||
|
|
||||||
|
#define BS_DrvNum 36
|
||||||
|
#define BS_BootSig 38
|
||||||
|
#define BS_VolID 39
|
||||||
|
#define BS_VolLab 43
|
||||||
|
#define BS_FilSysType 54
|
||||||
|
|
||||||
|
#define BPB_FATSz32 36
|
||||||
|
#define BPB_ExtFlags 40
|
||||||
|
#define BPB_FSVer 42
|
||||||
|
#define BPB_RootClus 44
|
||||||
|
#define BPB_FSInfo 48
|
||||||
|
#define BPB_BkBootSec 50
|
||||||
|
#define BS_DrvNum32 64
|
||||||
|
#define BS_BootSig32 66
|
||||||
|
#define BS_VolID32 67
|
||||||
|
#define BS_VolLab32 71
|
||||||
|
#define BS_FilSysType32 82
|
||||||
|
|
||||||
|
#define FSI_LeadSig 0
|
||||||
|
#define FSI_StrucSig 484
|
||||||
|
#define FSI_Free_Count 488
|
||||||
|
#define FSI_Nxt_Free 492
|
||||||
|
|
||||||
|
#define MBR_Table 446
|
||||||
|
|
||||||
|
#define DIR_Name 0
|
||||||
|
#define DIR_Attr 11
|
||||||
|
#define DIR_NTres 12
|
||||||
|
#define DIR_CrtTime 14
|
||||||
|
#define DIR_CrtDate 16
|
||||||
|
#define DIR_FstClusHI 20
|
||||||
|
#define DIR_WrtTime 22
|
||||||
|
#define DIR_WrtDate 24
|
||||||
|
#define DIR_FstClusLO 26
|
||||||
|
#define DIR_FileSize 28
|
||||||
|
#define LDIR_Ord 0
|
||||||
|
#define LDIR_Attr 11
|
||||||
|
#define LDIR_Type 12
|
||||||
|
#define LDIR_Chksum 13
|
||||||
|
#define LDIR_FstClusLO 26
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------*/
|
||||||
|
/* Multi-byte word access macros */
|
||||||
|
|
||||||
|
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
|
||||||
|
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
|
||||||
|
#else /* Use byte-by-byte access to the FAT structure */
|
||||||
|
#define LD_WORD(ptr) (WORD)(((WORD)*(BYTE*)((ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
|
||||||
|
#define LD_DWORD(ptr) (DWORD)(((DWORD)*(BYTE*)((ptr)+3)<<24)|((DWORD)*(BYTE*)((ptr)+2)<<16)|((WORD)*(BYTE*)((ptr)+1)<<8)|*(BYTE*)(ptr))
|
||||||
|
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8)
|
||||||
|
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *(BYTE*)((ptr)+1)=(BYTE)((WORD)(val)>>8); *(BYTE*)((ptr)+2)=(BYTE)((DWORD)(val)>>16); *(BYTE*)((ptr)+3)=(BYTE)((DWORD)(val)>>24)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _FATFS */
|
||||||
@@ -1,525 +0,0 @@
|
|||||||
#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
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
#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
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
|
|
||||||
#ifndef _HARDWARE_H
|
|
||||||
/*
|
|
||||||
hier sind die beiden hardware abhängigen bibliotheken zu includen !
|
|
||||||
welchen umfang diese haben müssen (an funktionen), muss man in den bibliotheken nachsehen.
|
|
||||||
*/
|
|
||||||
#define _HARDWARE_H
|
|
||||||
#include "uart.h"
|
|
||||||
#include "mmc.h"
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
37
avr/usbload/integer.h
Normal file
37
avr/usbload/integer.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*-------------------------------------------*/
|
||||||
|
/* Integer type definitions for FatFs module */
|
||||||
|
/*-------------------------------------------*/
|
||||||
|
|
||||||
|
#ifndef _INTEGER
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
typedef enum { FALSE = 0, TRUE } BOOL;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _INTEGER
|
||||||
|
#endif
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
File: main.smc
|
File: main.smc
|
||||||
Time: Sun, 09 Aug 2009 11:41:19
|
Time: Thu, 06 Aug 2009 20:01:38
|
||||||
*/
|
*/
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include <loader.h>
|
#include <loader.h>
|
||||||
|
|||||||
@@ -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_FAT);
|
uint8_t debug_level = (DEBUG | DEBUG_USB | DEBUG_CRC);
|
||||||
|
|
||||||
uint8_t read_buffer[TRANSFER_BUFFER_SIZE];
|
uint8_t read_buffer[TRANSFER_BUFFER_SIZE];
|
||||||
uint32_t req_addr = 0;
|
uint32_t req_addr = 0;
|
||||||
@@ -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(DEBUG_USB,
|
debug(DEBUG_USB,
|
||||||
// "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);
|
||||||
}
|
}
|
||||||
@@ -283,15 +283,20 @@ void usb_connect()
|
|||||||
void boot_startup_rom()
|
void boot_startup_rom()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
info("Activate AVR bus\n");
|
info("Activate AVR bus\n");
|
||||||
avr_bus_active();
|
avr_bus_active();
|
||||||
|
|
||||||
info("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");
|
info("Set Snes lowrom \n");
|
||||||
|
|
||||||
rle_decode(&_rom, ROM_BUFFER_SIZE, 0x000000);
|
rle_decode(&_rom, ROM_BUFFER_SIZE, 0x000000);
|
||||||
dump_memory(0x10000 - 0x100, 0x10000);
|
dump_memory(0x10000 - 0x100, 0x10000);
|
||||||
|
|
||||||
snes_reset_hi();
|
snes_reset_hi();
|
||||||
snes_reset_off();
|
snes_reset_off();
|
||||||
snes_irq_lo();
|
snes_irq_lo();
|
||||||
@@ -302,9 +307,20 @@ void boot_startup_rom()
|
|||||||
info("Disable snes WR\n");
|
info("Disable snes WR\n");
|
||||||
snes_bus_active();
|
snes_bus_active();
|
||||||
info("Activate Snes bus\n");
|
info("Activate Snes bus\n");
|
||||||
_delay_ms(20);
|
_delay_ms(100);
|
||||||
|
info("Reset Snes\n");
|
||||||
send_reset();
|
send_reset();
|
||||||
_delay_ms(200);
|
_delay_ms(100);
|
||||||
|
#if 0
|
||||||
|
uint8_t i = 0;
|
||||||
|
i = 20;
|
||||||
|
info("Wait");
|
||||||
|
while (--i) {
|
||||||
|
_delay_ms(500);
|
||||||
|
info(".");
|
||||||
|
}
|
||||||
|
info("\n");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -314,34 +330,23 @@ int main(void)
|
|||||||
uart_init();
|
uart_init();
|
||||||
stdout = &uart_stdout;
|
stdout = &uart_stdout;
|
||||||
|
|
||||||
|
|
||||||
info("Sytem start\n");
|
info("Sytem start\n");
|
||||||
system_init();
|
system_init();
|
||||||
|
|
||||||
|
#if 0
|
||||||
#if 1
|
test_read_write();
|
||||||
avr_bus_active();
|
test_bulk_read_write();
|
||||||
info("Activate AVR bus\n");
|
test_crc();
|
||||||
info("IRQ off\n");
|
while (1);
|
||||||
snes_irq_lo();
|
|
||||||
snes_irq_off();
|
|
||||||
info("Set Snes lowrom\n");
|
|
||||||
snes_lorom();
|
|
||||||
info("Disable snes WR\n");
|
|
||||||
snes_wr_disable();
|
|
||||||
test_sdcard();
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
info("Boot startup rom\n");
|
info("Boot startup rom\n");
|
||||||
boot_startup_rom();
|
boot_startup_rom();
|
||||||
|
|
||||||
|
|
||||||
usbInit();
|
usbInit();
|
||||||
usb_connect();
|
usb_connect();
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
|
|
||||||
avr_bus_active();
|
avr_bus_active();
|
||||||
info("Activate AVR bus\n");
|
info("Activate AVR bus\n");
|
||||||
info("IRQ off\n");
|
info("IRQ off\n");
|
||||||
@@ -364,6 +369,7 @@ int main(void)
|
|||||||
snes_bus_active();
|
snes_bus_active();
|
||||||
info("Activate Snes bus\n");
|
info("Activate Snes bus\n");
|
||||||
_delay_ms(100);
|
_delay_ms(100);
|
||||||
|
info("Reset Snes\n");
|
||||||
send_reset();
|
send_reset();
|
||||||
|
|
||||||
info("Poll\n");
|
info("Poll\n");
|
||||||
@@ -405,8 +411,6 @@ int main(void)
|
|||||||
info("Read 0x3000=%c\n", c);
|
info("Read 0x3000=%c\n", c);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
info("Boot startup rom\n");
|
|
||||||
boot_startup_rom();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -1,220 +1,600 @@
|
|||||||
/*
|
/*-----------------------------------------------------------------------*/
|
||||||
* ####################################################################################### Connect AVR to MMC/SD
|
/* MMC/SDSC/SDHC (in SPI mode) control module (C)ChaN, 2007 */
|
||||||
*
|
/*-----------------------------------------------------------------------*/
|
||||||
* Copyright (C) 2004 Ulrich Radig
|
/* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
|
||||||
*
|
/* are platform dependent. */
|
||||||
* 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 <avr/io.h>
|
||||||
#include <util/delay.h>
|
#include "diskio.h"
|
||||||
|
|
||||||
#include "mmc.h"
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t mmc_init()
|
/* Definitions for MMC/SDC command */
|
||||||
|
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
|
||||||
|
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
|
||||||
|
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
|
||||||
|
#define CMD8 (0x40+8) /* SEND_IF_COND */
|
||||||
|
#define CMD9 (0x40+9) /* SEND_CSD */
|
||||||
|
#define CMD10 (0x40+10) /* SEND_CID */
|
||||||
|
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
|
||||||
|
#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
|
||||||
|
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
|
||||||
|
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
|
||||||
|
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
|
||||||
|
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
|
||||||
|
#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
|
||||||
|
#define CMD24 (0x40+24) /* WRITE_BLOCK */
|
||||||
|
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
|
||||||
|
#define CMD55 (0x40+55) /* APP_CMD */
|
||||||
|
#define CMD58 (0x40+58) /* READ_OCR */
|
||||||
|
|
||||||
|
|
||||||
|
/* Port Controls (Platform dependent) */
|
||||||
|
#define SELECT() PORTB &= ~1 /* MMC CS = L */
|
||||||
|
#define DESELECT() PORTB |= 1 /* MMC CS = H */
|
||||||
|
|
||||||
|
#define SOCKPORT PINB /* Socket contact port */
|
||||||
|
#define SOCKWP 0x20 /* Write protect switch (PB5) */
|
||||||
|
#define SOCKINS 0x10 /* Card detect switch (PB4) */
|
||||||
|
|
||||||
|
#define FCLK_SLOW() /* Set slow clock (100k-400k) */
|
||||||
|
#define FCLK_FAST() /* Set fast clock (depends on the CSD) */
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Module Private Functions
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static volatile
|
||||||
|
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||||
|
|
||||||
|
static volatile
|
||||||
|
BYTE Timer1, Timer2; /* 100Hz decrement timer */
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE CardType; /* Card type flags */
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Transmit a byte to MMC via SPI (Platform dependent) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#define xmit_spi(dat) SPDR=(dat); loop_until_bit_is_set(SPSR,SPIF)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Receive a byte from MMC via SPI (Platform dependent) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE rcvr_spi (void)
|
||||||
{
|
{
|
||||||
uint16_t Timeout = 0, i;
|
SPDR = 0xFF;
|
||||||
MMC_REG |= ((1 << MMC_DO) | (1 << MMC_CS) | (1 << MMC_CLK));
|
loop_until_bit_is_set(SPSR, SPIF);
|
||||||
MMC_REG &= ~(1 << MMC_DI);
|
return SPDR;
|
||||||
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)
|
|
||||||
|
/* Alternative macro to receive data fast */
|
||||||
|
#define rcvr_spi_m(dst) SPDR=0xFF; loop_until_bit_is_set(SPSR,SPIF); *(dst)=SPDR
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Wait for card ready */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE wait_ready (void)
|
||||||
{
|
{
|
||||||
uint8_t tmp = 0xff;
|
BYTE res;
|
||||||
uint16_t Timeout = 0;
|
|
||||||
uint8_t a;
|
|
||||||
|
|
||||||
for (a = 0; a < 0x06; a++) {
|
|
||||||
mmc_write_byte(*cmd++);
|
|
||||||
}
|
|
||||||
|
|
||||||
while (tmp == 0xff) {
|
Timer2 = 50; /* Wait for ready in timeout of 500ms */
|
||||||
tmp = mmc_read_byte();
|
rcvr_spi();
|
||||||
if (Timeout++ > 50) {
|
do
|
||||||
break;
|
res = rcvr_spi();
|
||||||
}
|
while ((res != 0xFF) && Timer2);
|
||||||
}
|
|
||||||
return (tmp);
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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;
|
/* Deselect the card and release SPI bus */
|
||||||
}
|
/*-----------------------------------------------------------------------*/
|
||||||
MMC_WRITE &= ~(1 << MMC_CLK);
|
|
||||||
_delay_us(4);
|
static
|
||||||
}
|
void release_spi (void)
|
||||||
return (Byte);
|
{
|
||||||
|
DESELECT();
|
||||||
|
rcvr_spi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
/* Power Control (Platform dependent) */
|
||||||
}
|
/*-----------------------------------------------------------------------*/
|
||||||
Byte = (Byte << 1);
|
/* When the target system does not support socket power control, there */
|
||||||
MMC_WRITE |= (1 << MMC_CLK);
|
/* is nothing to do in these functions and chk_power always returns 1. */
|
||||||
_delay_us(4);
|
|
||||||
MMC_WRITE &= ~(1 << MMC_CLK);
|
static
|
||||||
_delay_us(4);
|
void power_on (void)
|
||||||
}
|
{
|
||||||
MMC_WRITE |= (1 << MMC_DO);
|
PORTE &= ~0x80; /* Socket power ON */
|
||||||
|
for (Timer1 = 3; Timer1; ); /* Wait for 30ms */
|
||||||
|
PORTB = 0b10110101; /* Enable drivers */
|
||||||
|
DDRB = 0b11000111;
|
||||||
|
SPCR = 0b01010000; /* Initialize SPI port (Mode 0) */
|
||||||
|
SPSR = 0b00000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t mmc_write_sector(uint32_t addr, uint8_t * Buffer)
|
static
|
||||||
|
void power_off (void)
|
||||||
{
|
{
|
||||||
uint8_t tmp;
|
SELECT(); /* Wait for card ready */
|
||||||
|
wait_ready();
|
||||||
|
release_spi();
|
||||||
|
|
||||||
|
SPCR = 0; /* Disable SPI function */
|
||||||
|
DDRB = 0b11000000; /* Disable drivers */
|
||||||
|
PORTB = 0b10110000;
|
||||||
|
PORTE |= 0x80; /* Socket power OFF */
|
||||||
|
Stat |= STA_NOINIT; /* Set STA_NOINIT */
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t cmd[] = { 0x58, 0x00, 0x00, 0x00, 0x00, 0xFF };
|
static
|
||||||
uint8_t a;
|
int chk_power(void) /* Socket power state: 0=off, 1=on */
|
||||||
uint16_t i;
|
{
|
||||||
|
return (PORTE & 0x80) ? 0 : 1;
|
||||||
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)
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Receive a data packet from MMC */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static
|
||||||
|
BOOL rcvr_datablock (
|
||||||
|
BYTE *buff, /* Data buffer to store received data */
|
||||||
|
UINT btr /* Byte count (must be multiple of 4) */
|
||||||
|
)
|
||||||
{
|
{
|
||||||
uint16_t a;
|
BYTE token;
|
||||||
|
|
||||||
if (mmc_write_command(cmd) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (mmc_read_byte() != 0xfe) {
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
for (a = 0; a < Bytes; a++) {
|
Timer1 = 10;
|
||||||
*Buffer++ = mmc_read_byte();
|
do { /* Wait for data packet in timeout of 100ms */
|
||||||
}
|
token = rcvr_spi();
|
||||||
|
} while ((token == 0xFF) && Timer1);
|
||||||
|
if(token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
|
||||||
|
|
||||||
mmc_read_byte();
|
do { /* Receive the data block into buffer */
|
||||||
mmc_read_byte();
|
rcvr_spi_m(buff++);
|
||||||
return;
|
rcvr_spi_m(buff++);
|
||||||
}
|
rcvr_spi_m(buff++);
|
||||||
|
rcvr_spi_m(buff++);
|
||||||
|
} while (btr -= 4);
|
||||||
|
rcvr_spi(); /* Discard CRC */
|
||||||
|
rcvr_spi();
|
||||||
|
|
||||||
uint8_t mmc_read_sector(uint32_t addr, uint8_t * Buffer)
|
return TRUE; /* Return with success */
|
||||||
{
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
/* Send a data packet to MMC */
|
||||||
return (0);
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if _READONLY == 0
|
||||||
|
static
|
||||||
|
BOOL xmit_datablock (
|
||||||
|
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||||
|
BYTE token /* Data/Stop token */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BYTE resp, wc;
|
||||||
|
|
||||||
|
|
||||||
|
if (wait_ready() != 0xFF) return FALSE;
|
||||||
|
|
||||||
|
xmit_spi(token); /* Xmit data token */
|
||||||
|
if (token != 0xFD) { /* Is data token */
|
||||||
|
wc = 0;
|
||||||
|
do { /* Xmit the 512 byte data block to MMC */
|
||||||
|
xmit_spi(*buff++);
|
||||||
|
xmit_spi(*buff++);
|
||||||
|
} while (--wc);
|
||||||
|
xmit_spi(0xFF); /* CRC (Dummy) */
|
||||||
|
xmit_spi(0xFF);
|
||||||
|
resp = rcvr_spi(); /* Reveive data response */
|
||||||
|
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
#endif /* _READONLY */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Send a command packet to MMC */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
static
|
||||||
|
BYTE send_cmd (
|
||||||
|
BYTE cmd, /* Command byte */
|
||||||
|
DWORD arg /* Argument */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BYTE n, res;
|
||||||
|
|
||||||
|
|
||||||
|
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
|
||||||
|
cmd &= 0x7F;
|
||||||
|
res = send_cmd(CMD55, 0);
|
||||||
|
if (res > 1) return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Select the card and wait for ready */
|
||||||
|
DESELECT();
|
||||||
|
SELECT();
|
||||||
|
if (wait_ready() != 0xFF) return 0xFF;
|
||||||
|
|
||||||
|
/* Send command packet */
|
||||||
|
xmit_spi(cmd); /* Start + Command index */
|
||||||
|
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||||
|
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||||
|
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||||
|
xmit_spi((BYTE)arg); /* Argument[7..0] */
|
||||||
|
n = 0x01; /* Dummy CRC + Stop */
|
||||||
|
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
|
||||||
|
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
|
||||||
|
xmit_spi(n);
|
||||||
|
|
||||||
|
/* Receive command response */
|
||||||
|
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
|
||||||
|
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||||
|
do
|
||||||
|
res = rcvr_spi();
|
||||||
|
while ((res & 0x80) && --n);
|
||||||
|
|
||||||
|
return res; /* Return with the response value */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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);
|
Public Functions
|
||||||
|
|
||||||
|
---------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Initialize Disk Drive */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_initialize (
|
||||||
|
BYTE drv /* Physical drive nmuber (0) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
BYTE n, cmd, ty, ocr[4];
|
||||||
|
|
||||||
|
|
||||||
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||||
|
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
||||||
|
|
||||||
|
power_on(); /* Force socket power on */
|
||||||
|
FCLK_SLOW();
|
||||||
|
for (n = 10; n; n--) rcvr_spi(); /* 80 dummy clocks */
|
||||||
|
|
||||||
|
ty = 0;
|
||||||
|
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||||
|
Timer1 = 100; /* Initialization timeout of 1000 msec */
|
||||||
|
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDHC */
|
||||||
|
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
|
||||||
|
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||||
|
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
|
||||||
|
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
|
||||||
|
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||||
|
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* SDSC or MMC */
|
||||||
|
if (send_cmd(ACMD41, 0) <= 1) {
|
||||||
|
ty = CT_SD1; cmd = ACMD41; /* SDSC */
|
||||||
|
} else {
|
||||||
|
ty = CT_MMC; cmd = CMD1; /* MMC */
|
||||||
|
}
|
||||||
|
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
|
||||||
|
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
|
||||||
|
ty = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CardType = ty;
|
||||||
|
release_spi();
|
||||||
|
|
||||||
|
if (ty) { /* Initialization succeded */
|
||||||
|
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||||
|
FCLK_FAST();
|
||||||
|
} else { /* Initialization failed */
|
||||||
|
power_off();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Stat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Get Disk Status */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DSTATUS disk_status (
|
||||||
|
BYTE drv /* Physical drive nmuber (0) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||||
|
return Stat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Read Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
DRESULT disk_read (
|
||||||
|
BYTE drv, /* Physical drive nmuber (0) */
|
||||||
|
BYTE *buff, /* Pointer to the data buffer to store read data */
|
||||||
|
DWORD sector, /* Start sector number (LBA) */
|
||||||
|
BYTE count /* Sector count (1..255) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (drv || !count) return RES_PARERR;
|
||||||
|
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||||
|
|
||||||
|
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||||
|
|
||||||
|
if (count == 1) { /* Single block read */
|
||||||
|
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||||
|
&& rcvr_datablock(buff, 512))
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
else { /* Multiple block read */
|
||||||
|
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||||
|
do {
|
||||||
|
if (!rcvr_datablock(buff, 512)) break;
|
||||||
|
buff += 512;
|
||||||
|
} while (--count);
|
||||||
|
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_spi();
|
||||||
|
|
||||||
|
return count ? RES_ERROR : RES_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Write Sector(s) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if _READONLY == 0
|
||||||
|
DRESULT disk_write (
|
||||||
|
BYTE drv, /* Physical drive nmuber (0) */
|
||||||
|
const BYTE *buff, /* Pointer to the data to be written */
|
||||||
|
DWORD sector, /* Start sector number (LBA) */
|
||||||
|
BYTE count /* Sector count (1..255) */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (drv || !count) return RES_PARERR;
|
||||||
|
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||||
|
if (Stat & STA_PROTECT) return RES_WRPRT;
|
||||||
|
|
||||||
|
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
|
||||||
|
|
||||||
|
if (count == 1) { /* Single block write */
|
||||||
|
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||||
|
&& xmit_datablock(buff, 0xFE))
|
||||||
|
count = 0;
|
||||||
|
}
|
||||||
|
else { /* Multiple block write */
|
||||||
|
if (CardType & CT_SDC) send_cmd(ACMD23, count);
|
||||||
|
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||||
|
do {
|
||||||
|
if (!xmit_datablock(buff, 0xFC)) break;
|
||||||
|
buff += 512;
|
||||||
|
} while (--count);
|
||||||
|
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
||||||
|
count = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
release_spi();
|
||||||
|
|
||||||
|
return count ? RES_ERROR : RES_OK;
|
||||||
|
}
|
||||||
|
#endif /* _READONLY == 0 */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Miscellaneous Functions */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#if _USE_IOCTL != 0
|
||||||
|
DRESULT disk_ioctl (
|
||||||
|
BYTE drv, /* Physical drive nmuber (0) */
|
||||||
|
BYTE ctrl, /* Control code */
|
||||||
|
void *buff /* Buffer to send/receive control data */
|
||||||
|
)
|
||||||
|
{
|
||||||
|
DRESULT res;
|
||||||
|
BYTE n, csd[16], *ptr = buff;
|
||||||
|
WORD csize;
|
||||||
|
|
||||||
|
|
||||||
|
if (drv) return RES_PARERR;
|
||||||
|
|
||||||
|
res = RES_ERROR;
|
||||||
|
|
||||||
|
if (ctrl == CTRL_POWER) {
|
||||||
|
switch (*ptr) {
|
||||||
|
case 0: /* Sub control code == 0 (POWER_OFF) */
|
||||||
|
if (chk_power())
|
||||||
|
power_off(); /* Power off */
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
case 1: /* Sub control code == 1 (POWER_ON) */
|
||||||
|
power_on(); /* Power on */
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
case 2: /* Sub control code == 2 (POWER_GET) */
|
||||||
|
*(ptr+1) = (BYTE)chk_power();
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
res = RES_PARERR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||||
|
|
||||||
|
switch (ctrl) {
|
||||||
|
case CTRL_SYNC : /* Make sure that no pending write process */
|
||||||
|
SELECT();
|
||||||
|
if (wait_ready() == 0xFF)
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||||
|
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||||
|
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||||
|
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
||||||
|
*(DWORD*)buff = (DWORD)csize << 10;
|
||||||
|
} else { /* SDC ver 1.XX or MMC*/
|
||||||
|
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
|
||||||
|
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
|
||||||
|
*(DWORD*)buff = (DWORD)csize << (n - 9);
|
||||||
|
}
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
|
||||||
|
*(WORD*)buff = 512;
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
|
||||||
|
if (CardType & CT_SD2) { /* SDC ver 2.00 */
|
||||||
|
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
|
||||||
|
rcvr_spi();
|
||||||
|
if (rcvr_datablock(csd, 16)) { /* Read partial block */
|
||||||
|
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
|
||||||
|
*(DWORD*)buff = 16UL << (csd[10] >> 4);
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { /* SDC ver 1.XX or MMC */
|
||||||
|
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
|
||||||
|
if (CardType & CT_SD1) { /* SDC ver 1.XX */
|
||||||
|
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
|
||||||
|
} else { /* MMC */
|
||||||
|
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
|
||||||
|
}
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
|
||||||
|
*ptr = CardType;
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
|
||||||
|
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
|
||||||
|
&& rcvr_datablock(ptr, 16))
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
|
||||||
|
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
|
||||||
|
&& rcvr_datablock(ptr, 16))
|
||||||
|
res = RES_OK;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
|
||||||
|
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
|
||||||
|
for (n = 4; n; n--) *ptr++ = rcvr_spi();
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
|
||||||
|
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
|
||||||
|
rcvr_spi();
|
||||||
|
if (rcvr_datablock(ptr, 64))
|
||||||
|
res = RES_OK;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
res = RES_PARERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
release_spi();
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
#endif /* _USE_IOCTL != 0 */
|
||||||
|
|
||||||
|
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* Device Timer Interrupt Procedure (Platform dependent) */
|
||||||
|
/*-----------------------------------------------------------------------*/
|
||||||
|
/* This function must be called in period of 10ms */
|
||||||
|
|
||||||
|
void disk_timerproc (void)
|
||||||
|
{
|
||||||
|
static BYTE pv;
|
||||||
|
BYTE n, s;
|
||||||
|
|
||||||
|
|
||||||
|
n = Timer1; /* 100Hz decrement timer */
|
||||||
|
if (n) Timer1 = --n;
|
||||||
|
n = Timer2;
|
||||||
|
if (n) Timer2 = --n;
|
||||||
|
|
||||||
|
n = pv;
|
||||||
|
pv = SOCKPORT & (SOCKWP | SOCKINS); /* Sample socket switch */
|
||||||
|
|
||||||
|
if (n == pv) { /* Have contacts stabled? */
|
||||||
|
s = Stat;
|
||||||
|
|
||||||
|
if (pv & SOCKWP) /* WP is H (write protected) */
|
||||||
|
s |= STA_PROTECT;
|
||||||
|
else /* WP is L (write enabled) */
|
||||||
|
s &= ~STA_PROTECT;
|
||||||
|
|
||||||
|
if (pv & SOCKINS) /* INS = H (Socket empty) */
|
||||||
|
s |= (STA_NODISK | STA_NOINIT);
|
||||||
|
else /* INS = L (Card inserted) */
|
||||||
|
s &= ~STA_NODISK;
|
||||||
|
|
||||||
|
Stat = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* ####################################################################################### 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
|
|
||||||
@@ -22,9 +22,9 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <avr/pgmspace.h> /* required by usbdrv.h */
|
#include <avr/pgmspace.h>
|
||||||
#include <util/delay.h> /* for _delay_ms() */
|
#include <util/delay.h>
|
||||||
#include <avr/interrupt.h> /* for sei() */
|
#include <avr/interrupt.h>
|
||||||
|
|
||||||
#include "sram.h"
|
#include "sram.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|||||||
44
avr/usbload/rtc.c
Normal file
44
avr/usbload/rtc.c
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/*--------------------------------------------------------------------------*/
|
||||||
|
/* RTC controls */
|
||||||
|
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "rtc.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOL rtc_gettime (RTC *rtc)
|
||||||
|
{
|
||||||
|
BYTE buf[8];
|
||||||
|
|
||||||
|
|
||||||
|
rtc->sec = (buf[0] & 0x0F) + ((buf[0] >> 4) & 7) * 10;
|
||||||
|
rtc->min = (buf[1] & 0x0F) + (buf[1] >> 4) * 10;
|
||||||
|
rtc->hour = (buf[2] & 0x0F) + ((buf[2] >> 4) & 3) * 10;
|
||||||
|
rtc->wday = (buf[2] & 0x07);
|
||||||
|
rtc->mday = (buf[4] & 0x0F) + ((buf[4] >> 4) & 3) * 10;
|
||||||
|
rtc->month = (buf[5] & 0x0F) + ((buf[5] >> 4) & 1) * 10;
|
||||||
|
rtc->year = 2000 + (buf[6] & 0x0F) + (buf[6] >> 4) * 10;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BOOL rtc_settime (const RTC *rtc)
|
||||||
|
{
|
||||||
|
|
||||||
|
BYTE buf[8];
|
||||||
|
|
||||||
|
|
||||||
|
buf[0] = rtc->sec / 10 * 16 + rtc->sec % 10;
|
||||||
|
buf[1] = rtc->min / 10 * 16 + rtc->min % 10;
|
||||||
|
buf[2] = rtc->hour / 10 * 16 + rtc->hour % 10;
|
||||||
|
buf[3] = rtc->wday & 7;
|
||||||
|
buf[4] = rtc->mday / 10 * 16 + rtc->mday % 10;
|
||||||
|
buf[5] = rtc->month / 10 * 16 + rtc->month % 10;
|
||||||
|
buf[6] = (rtc->year - 2000) / 10 * 16 + (rtc->year - 2000) % 10;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
15
avr/usbload/rtc.h
Normal file
15
avr/usbload/rtc.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
#include "integer.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
WORD year; /* 2000..2099 */
|
||||||
|
BYTE month; /* 1..12 */
|
||||||
|
BYTE mday; /* 1.. 31 */
|
||||||
|
BYTE wday; /* 1..7 */
|
||||||
|
BYTE hour; /* 0..23 */
|
||||||
|
BYTE min; /* 0..59 */
|
||||||
|
BYTE sec; /* 0..59 */
|
||||||
|
} RTC;
|
||||||
|
|
||||||
|
BOOL rtc_gettime (RTC*); /* Get time */
|
||||||
|
BOOL rtc_settime (const RTC*); /* Set time */
|
||||||
|
|
||||||
@@ -73,7 +73,6 @@ void shared_memory_write(uint8_t cmd, uint8_t value)
|
|||||||
debug(DEBUG_SHM,"shared_memory_write: 0x%04x=0x%02x 0x%04x=0x%02x \n",
|
debug(DEBUG_SHM,"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();
|
|
||||||
shared_memory_scratchpad_tx_save();
|
shared_memory_scratchpad_tx_save();
|
||||||
shared_memory_irq_hook();
|
shared_memory_irq_hook();
|
||||||
|
|
||||||
@@ -82,7 +81,6 @@ void shared_memory_write(uint8_t cmd, uint8_t value)
|
|||||||
sram_write(SHARED_MEM_TX_LOC_PAYLOAD, value);
|
sram_write(SHARED_MEM_TX_LOC_PAYLOAD, value);
|
||||||
|
|
||||||
snes_hirom();
|
snes_hirom();
|
||||||
snes_wr_disable();
|
|
||||||
snes_bus_active();
|
snes_bus_active();
|
||||||
|
|
||||||
#if SHARED_MEM_SWITCH_IRQ
|
#if SHARED_MEM_SWITCH_IRQ
|
||||||
@@ -96,14 +94,10 @@ void shared_memory_write(uint8_t cmd, uint8_t value)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
avr_bus_active();
|
avr_bus_active();
|
||||||
snes_irq_lo();
|
|
||||||
snes_irq_off();
|
|
||||||
snes_lorom();
|
snes_lorom();
|
||||||
snes_wr_disable();
|
|
||||||
|
|
||||||
shared_memory_scratchpad_tx_restore();
|
shared_memory_scratchpad_tx_restore();
|
||||||
shared_memory_irq_restore();
|
shared_memory_irq_restore();
|
||||||
sram_bulk_addr_restore();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,13 +118,10 @@ 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;
|
||||||
|
|
||||||
|
|
||||||
state = sram_read(SHARED_MEM_RX_LOC_STATE);
|
state = sram_read(SHARED_MEM_RX_LOC_STATE);
|
||||||
if (state != SHARED_MEM_RX_AVR_ACK){
|
if (state != SHARED_MEM_RX_AVR_ACK){
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
sram_bulk_addr_save();
|
|
||||||
|
|
||||||
*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);
|
||||||
@@ -141,7 +132,6 @@ int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer)
|
|||||||
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();
|
||||||
snes_wr_disable();
|
|
||||||
snes_bus_active();
|
snes_bus_active();
|
||||||
|
|
||||||
#if SHARED_MEM_SWITCH_IRQ
|
#if SHARED_MEM_SWITCH_IRQ
|
||||||
@@ -156,7 +146,5 @@ int shared_memory_read(uint8_t *cmd, uint8_t *len,uint8_t *buffer)
|
|||||||
|
|
||||||
avr_bus_active();
|
avr_bus_active();
|
||||||
snes_lorom();
|
snes_lorom();
|
||||||
snes_wr_disable();
|
|
||||||
sram_bulk_addr_restore();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,8 @@
|
|||||||
#define SHARED_IRQ_LOC_LO 0x00fffe
|
#define SHARED_IRQ_LOC_LO 0x00fffe
|
||||||
#define SHARED_IRQ_LOC_HI 0x00ffff
|
#define SHARED_IRQ_LOC_HI 0x00ffff
|
||||||
|
|
||||||
/* Use COP IRQ LOC for hooked IRQ handler */
|
#define SHARED_IRQ_HANDLER_LO 0x00
|
||||||
#define SHARED_IRQ_HANDLER_LO 0x0ffe4
|
#define SHARED_IRQ_HANDLER_HI 0x10
|
||||||
#define SHARED_IRQ_HANDLER_HI 0x0ffe5
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h> /* for _delay_ms() */
|
||||||
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "sram.h"
|
#include "sram.h"
|
||||||
@@ -30,10 +31,6 @@
|
|||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
|
|
||||||
uint32_t addr_current = 0;
|
|
||||||
uint32_t addr_stash = 0;
|
|
||||||
|
|
||||||
|
|
||||||
void system_init(void)
|
void system_init(void)
|
||||||
{
|
{
|
||||||
/*-------------------------------------------------*/
|
/*-------------------------------------------------*/
|
||||||
@@ -96,19 +93,19 @@ 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(DEBUG_SRAM,"sreg_set: addr=0x%08lx\n",addr);
|
debug(DEBUG_SREG,"sreg_set: addr=0x%08lx",addr);
|
||||||
while(i--) {
|
while(i--) {
|
||||||
if ((addr & ( 1L << i))){
|
if ((addr & ( 1L << i))){
|
||||||
debug(DEBUG_SRAM,"1");
|
debug(DEBUG_SREG,"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(DEBUG_SRAM,"0");
|
debug(DEBUG_SREG,"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(DEBUG_SRAM,"\n");
|
debug(DEBUG_SREG,"\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);
|
||||||
|
|
||||||
@@ -116,23 +113,11 @@ void sreg_set(uint32_t addr)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void sram_bulk_addr_save()
|
|
||||||
{
|
|
||||||
addr_stash = addr_current;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void sram_bulk_addr_restore()
|
|
||||||
{
|
|
||||||
sreg_set(addr_stash);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void sram_bulk_read_start(uint32_t addr)
|
void sram_bulk_read_start(uint32_t addr)
|
||||||
{
|
{
|
||||||
debug(DEBUG_SRAM,"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;
|
|
||||||
|
|
||||||
avr_data_in();
|
avr_data_in();
|
||||||
|
|
||||||
AVR_CS_PORT &= ~(1 << AVR_CS_PIN);
|
AVR_CS_PORT &= ~(1 << AVR_CS_PIN);
|
||||||
@@ -153,7 +138,6 @@ void sram_bulk_read_start(uint32_t addr)
|
|||||||
|
|
||||||
inline void sram_bulk_read_next(void)
|
inline void sram_bulk_read_next(void)
|
||||||
{
|
{
|
||||||
addr_current++;
|
|
||||||
AVR_RD_PORT |= (1 << AVR_RD_PIN);
|
AVR_RD_PORT |= (1 << AVR_RD_PIN);
|
||||||
counter_up();
|
counter_up();
|
||||||
AVR_RD_PORT &= ~(1 << AVR_RD_PIN);
|
AVR_RD_PORT &= ~(1 << AVR_RD_PIN);
|
||||||
|
|||||||
@@ -201,9 +201,4 @@ void sram_bulk_copy(uint32_t addr, uint8_t * src, uint32_t len);
|
|||||||
void sram_bulk_read_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_restore();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* =====================================================================================
|
* =====================================================================================
|
||||||
*
|
*
|
||||||
@@ -20,23 +22,31 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <string.h>
|
||||||
#include <stdint.h>
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include <avr/eeprom.h>
|
||||||
|
|
||||||
#include "shared_memory.h"
|
#include "usbdrv.h"
|
||||||
|
#include "oddebug.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "requests.h"
|
||||||
|
#include "uart.h"
|
||||||
#include "sram.h"
|
#include "sram.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "crc.h"
|
|
||||||
#include "config.h"
|
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
|
#include "dump.h"
|
||||||
#include "mmc.h"
|
#include "crc.h"
|
||||||
#include "fat.h"
|
#include "usb_bulk.h"
|
||||||
#include "file.h"
|
#include "timer.h"
|
||||||
#include "dir.h"
|
#include "watchdog.h"
|
||||||
|
#include "rle.h"
|
||||||
|
#include "loader.h"
|
||||||
|
#include "command.h"
|
||||||
|
#include "shared_memory.h"
|
||||||
|
#include "testing.h"
|
||||||
|
|
||||||
void test_read_write()
|
void test_read_write()
|
||||||
{
|
{
|
||||||
@@ -110,47 +120,145 @@ void test_crc()
|
|||||||
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();
|
/* FAT file system sample project for FatFs R0.06 (C)ChaN, 2008 */
|
||||||
printf("open %s\n",datei);
|
/*----------------------------------------------------------------------*/
|
||||||
ffopen( datei );
|
|
||||||
printf("open %s\n",datei);
|
#include "ff.h"
|
||||||
unsigned long int seek=file.length; // eine variable setzen und runterzählen bis 0 geht am schnellsten !
|
#include "diskio.h"
|
||||||
do{
|
#include "rtc.h"
|
||||||
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
|
|
||||||
|
DWORD acc_size; /* Work register for fs command */
|
||||||
|
WORD acc_files, acc_dirs;
|
||||||
|
FILINFO finfo;
|
||||||
|
|
||||||
|
|
||||||
|
FATFS fatfs[2]; /* File system object for each logical drive */
|
||||||
|
BYTE Buff[1024]; /* Working buffer */
|
||||||
|
|
||||||
|
volatile WORD Timer; /* 100Hz increment timer */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#if _MULTI_PARTITION != 0
|
||||||
|
const PARTITION Drives[] = { {0,0}, {0,1} };
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
ISR(TIMER2_COMP_vect)
|
||||||
|
{
|
||||||
|
Timer++;
|
||||||
|
disk_timerproc();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
DWORD get_fattime ()
|
||||||
|
{
|
||||||
|
RTC rtc;
|
||||||
|
|
||||||
|
|
||||||
|
//rtc_gettime(&rtc);
|
||||||
|
|
||||||
|
return ((DWORD)(rtc.year - 1980) << 25)
|
||||||
|
| ((DWORD)rtc.month << 21)
|
||||||
|
| ((DWORD)rtc.mday << 16)
|
||||||
|
| ((DWORD)rtc.hour << 11)
|
||||||
|
| ((DWORD)rtc.min << 5)
|
||||||
|
| ((DWORD)rtc.sec >> 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
FRESULT scan_files (char* path)
|
||||||
|
{
|
||||||
|
DIR dirs;
|
||||||
|
FRESULT res;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if ((res = f_opendir(&dirs, path)) == FR_OK) {
|
||||||
|
i = strlen(path);
|
||||||
|
while (((res = f_readdir(&dirs, &finfo)) == FR_OK) && finfo.fname[0]) {
|
||||||
|
if (finfo.fattrib & AM_DIR) {
|
||||||
|
acc_dirs++;
|
||||||
|
*(path+i) = '/'; strcpy(path+i+1, &finfo.fname[0]);
|
||||||
|
res = scan_files(path);
|
||||||
|
*(path+i) = '\0';
|
||||||
|
if (res != FR_OK) break;
|
||||||
|
} else {
|
||||||
|
acc_files++;
|
||||||
|
acc_size += finfo.fsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static
|
||||||
|
void put_rc (FRESULT rc)
|
||||||
|
{
|
||||||
|
const prog_char *p;
|
||||||
|
static const prog_char str[] =
|
||||||
|
"OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0"
|
||||||
|
"INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0"
|
||||||
|
"INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0";
|
||||||
|
FRESULT i;
|
||||||
|
|
||||||
|
for (p = str, i = 0; i != rc && pgm_read_byte_near(p); i++) {
|
||||||
|
while(pgm_read_byte_near(p++));
|
||||||
|
}
|
||||||
|
printf("rc=%u FR_%s\n", (WORD)rc, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void test_sdcard (void)
|
||||||
|
{
|
||||||
|
char *ptr, *ptr2;
|
||||||
|
DWORD p1, p2, p3;
|
||||||
|
BYTE res, b1;
|
||||||
|
WORD w1;
|
||||||
|
UINT s1, s2, cnt;
|
||||||
|
DWORD ofs, sect = 0;
|
||||||
|
RTC rtc;
|
||||||
|
FATFS *fs;
|
||||||
|
DIR dir; /* Directory object */
|
||||||
|
FIL file1, file2; /* File object */
|
||||||
|
|
||||||
|
|
||||||
|
printf("Try to init disk\n");
|
||||||
|
put_rc(f_mount((BYTE) 0, &fatfs[0]));
|
||||||
|
res = f_getfree("", &p2, &fs);
|
||||||
|
if (res)
|
||||||
|
put_rc(res);
|
||||||
|
|
||||||
|
printf( "FAT TYPE = %u\nBYTES/CLUSTER = %lu\nNUMBER OF FATS = %u\n"
|
||||||
|
"ROOT DIR ENTRIES = %u\nSECTORS/FAT = %lu\nNUMBER OF CLUSTERS = %lu\n"
|
||||||
|
"FAT START = %lu\nDIR START LBA,CLUSTER = %lu\nDATA START LBA = %lu\n",
|
||||||
|
(WORD) fs->fs_type, (DWORD) fs->csize * 512,
|
||||||
|
(WORD) fs->n_fats, fs->n_rootdir, (DWORD) fs->sects_fat,
|
||||||
|
(DWORD) fs->max_clust - 2, fs->fatbase, fs->dirbase, fs->database);
|
||||||
|
acc_size = acc_files = acc_dirs = 0;
|
||||||
|
|
||||||
|
printf("scan files\n");
|
||||||
|
res = scan_files("");
|
||||||
|
if (res)
|
||||||
|
put_rc(res);
|
||||||
|
printf("%u FILES, %lu BYTES\n%u FOLDERS\n"
|
||||||
|
"%lu KB TOTAK DISK SPACE\n%lu KB AVAILABLE\n", acc_files,
|
||||||
|
acc_size, acc_dirs, (fs->max_clust - 2) * (fs->csize / 2),
|
||||||
|
p2 * (fs->csize / 2));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -27,6 +27,5 @@ 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
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user