parent
9e251f7300
commit
6696ab7fd9
@ -0,0 +1,7 @@ |
||||
all: main |
||||
|
||||
main: main.c |
||||
gcc -std=gnu99 main.c fat16.c -o test -g
|
||||
|
||||
run: main |
||||
./test
|
@ -0,0 +1,462 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "fat16.h" |
||||
|
||||
|
||||
char* fat16_volume_label(const FAT16* fat, char* str) |
||||
{ |
||||
FAT16_FILE first; |
||||
fat16_open_root(fat, &first); |
||||
|
||||
if (first.type == FT_LABEL) { |
||||
return fat16_display_name(&first, str); |
||||
} |
||||
|
||||
// find where spaces end
|
||||
uint8_t j = 10; |
||||
for (; j >= 0; j--) |
||||
{ |
||||
if (fat->bs.volume_label[j] != ' ') break; |
||||
} |
||||
|
||||
// copy all until spaces
|
||||
uint8_t i; |
||||
for (i = 0; i <= j; i++) |
||||
{ |
||||
str[i] = fat->bs.volume_label[i]; |
||||
} |
||||
|
||||
str[i] = 0; // ender
|
||||
|
||||
return str; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* Resolve a file name, trim spaces and add null terminator. |
||||
* Returns the passed char*, or NULL on error. |
||||
*/ |
||||
char* fat16_display_name(const FAT16_FILE* file, char* str) |
||||
{ |
||||
// Cannot get name for special files
|
||||
if (file->type == FT_NONE || // not-yet-used directory location
|
||||
file->type == FT_DELETED || // deleted file entry
|
||||
file->attribs == 0x0F) // long name special entry (system, hidden)
|
||||
return NULL; |
||||
|
||||
// find first non-space
|
||||
uint8_t j = 7; |
||||
for (; j >= 0; j--) |
||||
{ |
||||
if (file->name[j] != ' ') break; |
||||
} |
||||
|
||||
// j ... last no-space char
|
||||
|
||||
uint8_t i; |
||||
for (i = 0; i <= j; i++) |
||||
{ |
||||
str[i] = file->name[i]; |
||||
} |
||||
|
||||
|
||||
// directory entry, no extension
|
||||
if (file->type == FT_SUBDIR || file->type == FT_SELF || file->type == FT_PARENT) |
||||
{ |
||||
str[i] = 0; // end of string
|
||||
return str; |
||||
} |
||||
|
||||
|
||||
// add a dot
|
||||
if (file->type != FT_LABEL) // volume label has no dot!
|
||||
str[i++] = '.'; |
||||
|
||||
// Add extension chars
|
||||
for (j = 0; j < 3; j++, i++) |
||||
{ |
||||
const char c = file->ext[j]; |
||||
if (c == ' ') break; |
||||
str[i] = c; |
||||
} |
||||
|
||||
str[i] = 0; // end of string
|
||||
|
||||
return str; |
||||
} |
||||
|
||||
|
||||
/** Read boot sector from given address */ |
||||
void _fat16_read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr); |
||||
|
||||
/**
|
||||
* Find absolute address of first BootSector. |
||||
* Returns 0 on failure. |
||||
*/ |
||||
uint32_t _fat16_find_bs(const BLOCKDEV* dev); |
||||
|
||||
|
||||
/** Get cluster's starting address */ |
||||
uint32_t _fat16_clu_start(const FAT16* fat, const uint16_t cluster); |
||||
|
||||
|
||||
/** Find following cluster using FAT for jumps */ |
||||
uint16_t _fat16_next_clu(const FAT16* fat, uint16_t cluster); |
||||
|
||||
|
||||
/** Find relative address in a file, using FAT for cluster lookup */ |
||||
uint32_t _fat16_clu_add(const FAT16* fat, uint16_t cluster, uint32_t addr); |
||||
|
||||
|
||||
/** Read a file entry from directory (dir starting cluster, entry number) */ |
||||
void _fat16_fopen(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num); |
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Find absolute address of first boot sector. |
||||
* Returns 0 on failure. |
||||
*/ |
||||
uint32_t _fat16_find_bs(const BLOCKDEV* dev) |
||||
{ |
||||
// Reference structure:
|
||||
//
|
||||
// typedef struct __attribute__((packed)) {
|
||||
// uint8_t first_byte;
|
||||
// uint8_t start_chs[3];
|
||||
// uint8_t partition_type;
|
||||
// uint8_t end_chs[3];
|
||||
// uint32_t start_sector;
|
||||
// uint32_t length_sectors;
|
||||
// } PartitionTable;
|
||||
|
||||
uint16_t addr = 0x1BE + 4; // fourth byte of structure is the type.
|
||||
uint32_t tmp = 0; |
||||
uint16_t tmp2; |
||||
|
||||
for (uint8_t i = 0; i < 4; i++, addr += 16) |
||||
{ |
||||
// Read partition type
|
||||
dev->aread(&tmp, 1, addr); |
||||
|
||||
// Check if type is valid
|
||||
if (tmp == 4 || tmp == 6 || tmp == 14) |
||||
{ |
||||
// read MBR address
|
||||
dev->rseek(3);// skip 3 bytes
|
||||
dev->read(&tmp, 4); |
||||
|
||||
tmp = tmp << 9; // multiply address by 512 (sector size)
|
||||
|
||||
// Verify that the boot sector has a valid signature mark
|
||||
dev->aread(&tmp2, 2, tmp + 510); |
||||
if (tmp2 != 0xAA55) continue; // continue to next entry
|
||||
|
||||
// return absolute MBR address
|
||||
return tmp; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void _fat16_read_bs(const BLOCKDEV* dev, Fat16BootSector* info, const uint32_t addr) |
||||
{ |
||||
dev->seek(addr + 13); // skip 13
|
||||
|
||||
dev->read(&(info->sectors_per_cluster), 6); // spc, rs, nf, re
|
||||
|
||||
info->total_sectors = 0; |
||||
dev->read(&(info->total_sectors), 2); // short sectors
|
||||
|
||||
dev->rseek(1); // md
|
||||
|
||||
dev->read(&(info->fat_size_sectors), 2); |
||||
|
||||
dev->rseek(8); // spt, noh, hs
|
||||
|
||||
// read or skip long sectors field
|
||||
if (info->total_sectors == 0) |
||||
{ |
||||
dev->read(&(info->total_sectors), 4); |
||||
} else |
||||
{ |
||||
dev->rseek(4); // tsl
|
||||
} |
||||
|
||||
dev->rseek(7); // dn, ch, bs, vi
|
||||
|
||||
dev->read(&(info->volume_label), 11); |
||||
} |
||||
|
||||
|
||||
/** Initialize a FAT16 handle */ |
||||
void fat16_init(const BLOCKDEV* dev, FAT16* fat) |
||||
{ |
||||
const uint32_t bs_a = _fat16_find_bs(dev); |
||||
fat->dev = dev; |
||||
_fat16_read_bs(dev, &(fat->bs), bs_a); |
||||
fat->fat_addr = bs_a + (fat->bs.reserved_sectors * 512); |
||||
fat->rd_addr = bs_a + (fat->bs.reserved_sectors + fat->bs.fat_size_sectors * fat->bs.num_fats) * 512; |
||||
fat->data_addr = fat->rd_addr + (fat->bs.root_entries * 32); // entry is 32B long
|
||||
|
||||
fat->bs.bytes_per_cluster = (fat->bs.sectors_per_cluster * 512); |
||||
} |
||||
|
||||
|
||||
/** Get cluster starting address */ |
||||
uint32_t _fat16_clu_start(const FAT16* fat, const uint16_t cluster) |
||||
{ |
||||
if (cluster < 2) return fat->rd_addr; |
||||
return fat->data_addr + (cluster - 2) * fat->bs.bytes_per_cluster; |
||||
} |
||||
|
||||
|
||||
uint16_t _fat16_next_clu(const FAT16* fat, uint16_t cluster) |
||||
{ |
||||
fat->dev->aread(&cluster, 2, fat->fat_addr + (cluster * 2)); |
||||
return cluster; |
||||
} |
||||
|
||||
|
||||
/** Find file-relative address in fat table */ |
||||
uint32_t _fat16_clu_add(const FAT16* fat, uint16_t cluster, uint32_t addr) |
||||
{ |
||||
while (addr >= fat->bs.bytes_per_cluster) |
||||
{ |
||||
cluster = _fat16_next_clu(fat, cluster); |
||||
if (cluster == 0xFFFF) return 0xFFFF; // fail
|
||||
addr -= fat->bs.bytes_per_cluster; |
||||
} |
||||
|
||||
return _fat16_clu_start(fat, cluster) + addr; |
||||
} |
||||
|
||||
|
||||
/** Move file cursor to a position relative to file start */ |
||||
bool fat16_fseek(FAT16_FILE* file, uint32_t addr) |
||||
{ |
||||
// Clamp.
|
||||
if (addr > file->size) |
||||
return false; |
||||
|
||||
// Store as rel
|
||||
file->cur_rel = addr; |
||||
|
||||
// Rewind and resolve abs, clu, ofs
|
||||
file->cur_clu = file->clu_start; |
||||
|
||||
while (addr >= file->fat->bs.bytes_per_cluster) |
||||
{ |
||||
file->cur_clu = _fat16_next_clu(file->fat, file->cur_clu); |
||||
addr -= file->fat->bs.bytes_per_cluster; |
||||
} |
||||
|
||||
file->cur_abs = _fat16_clu_start(file->fat, file->cur_clu) + addr; |
||||
file->cur_ofs = addr; |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* Read a file entry |
||||
* |
||||
* dir_cluster ... directory start cluster |
||||
* num ... entry number in the directory |
||||
*/ |
||||
void _fat16_fopen(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num) |
||||
{ |
||||
// Resolve starting address
|
||||
uint32_t addr; |
||||
if (dir_cluster == 0) |
||||
{ |
||||
addr = _fat16_clu_start(fat, dir_cluster) + num * 32; // root directory, max 512 entries.
|
||||
} else |
||||
{ |
||||
addr = _fat16_clu_add(fat, dir_cluster, num * 32); // cluster + N (wrapping to next cluster if needed)
|
||||
} |
||||
|
||||
fat->dev->aread(file, 12, addr); |
||||
fat->dev->rseek(14); // skip 14 bytes
|
||||
fat->dev->read(((void*)file) + 12, 6); // read remaining bytes
|
||||
|
||||
file->clu = dir_cluster; |
||||
file->num = num; |
||||
|
||||
// Resolve filename & type
|
||||
|
||||
file->type = FT_FILE; |
||||
|
||||
switch(file->name[0]) |
||||
{ |
||||
case 0x00: |
||||
file->type = FT_NONE; |
||||
return; |
||||
|
||||
case 0xE5: |
||||
file->type = FT_DELETED; |
||||
return; |
||||
|
||||
case 0x05: // Starting with 0xE5
|
||||
file->type = FT_FILE; |
||||
file->name[0] = 0xE5; // convert to the real character
|
||||
break; |
||||
|
||||
case 0x2E: |
||||
if (file->name[1] == 0x2E) |
||||
{ |
||||
// ".." directory
|
||||
file->type = FT_PARENT; |
||||
} else |
||||
{ |
||||
// "." directory
|
||||
file->type = FT_SELF; |
||||
} |
||||
break; |
||||
|
||||
default: |
||||
file->type = FT_FILE; |
||||
} |
||||
|
||||
// handle subdir, label
|
||||
if (file->attribs & FA_DIR && file->type == FT_FILE) |
||||
{ |
||||
file->type = FT_SUBDIR; |
||||
} else |
||||
if (file->attribs == FA_LABEL) |
||||
{ |
||||
file->type = FT_LABEL; // volume label special file
|
||||
} else |
||||
if (file->attribs == 0x0F) |
||||
{ |
||||
file->type = FT_LFN; // long name special file, can be safely ignored
|
||||
} |
||||
|
||||
// add a FAT pointer
|
||||
file->fat = fat; |
||||
|
||||
// Init cursors
|
||||
fat16_fseek(file, 0); |
||||
} |
||||
|
||||
|
||||
/**
|
||||
* Check if file is a valid entry (to be shown) |
||||
*/ |
||||
bool fat16_is_file_valid(const FAT16_FILE* file) |
||||
{ |
||||
switch (file->type) { |
||||
case FT_FILE: |
||||
case FT_SUBDIR: |
||||
case FT_SELF: |
||||
case FT_PARENT: |
||||
return true; |
||||
|
||||
default: |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
#define MIN(a, b) (((a) < (b)) ? (a) : (b)) |
||||
|
||||
bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len) |
||||
{ |
||||
if (file->cur_abs == 0xFFFF) |
||||
return false; // file at the end already
|
||||
|
||||
if (file->cur_rel + len > file->size) |
||||
return false; // attempt to read outside file size
|
||||
|
||||
while (len > 0 && file->cur_rel < file->size) |
||||
{ |
||||
uint16_t chunk = MIN(file->size - file->cur_rel, MIN(file->fat->bs.bytes_per_cluster - file->cur_ofs, len)); |
||||
|
||||
file->fat->dev->aread(target, chunk, file->cur_abs); |
||||
|
||||
file->cur_abs += chunk; |
||||
file->cur_rel += chunk; |
||||
file->cur_ofs += chunk; |
||||
|
||||
target += chunk; |
||||
|
||||
if (file->cur_ofs >= file->fat->bs.bytes_per_cluster) |
||||
{ |
||||
file->cur_clu = _fat16_next_clu(file->fat, file->cur_clu); |
||||
file->cur_abs = _fat16_clu_start(file->fat, file->cur_clu); |
||||
file->cur_ofs = 0; |
||||
} |
||||
|
||||
len -= chunk; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** Open next file in the directory */ |
||||
bool fat16_next(FAT16_FILE* file) |
||||
{ |
||||
if (file->clu == 0 && file->num >= file->fat->bs.root_entries) |
||||
return false; // attempt to read outside root directory.
|
||||
|
||||
uint32_t addr = _fat16_clu_add(file->fat, file->clu, (file->num + 1) * 32); |
||||
if (addr == 0xFFFF) |
||||
return false; // next file is out of the directory cluster
|
||||
|
||||
// read first byte of the file entry; if zero, can't read (file is NONE)
|
||||
// FIXME this may be a problem when creating a new file...
|
||||
uint8_t x; |
||||
file->fat->dev->aread(&x, 1, addr); |
||||
if (x == 0) |
||||
return false; |
||||
|
||||
_fat16_fopen(file->fat, file, file->clu, file->num+1); |
||||
|
||||
/* // Skip bad files
|
||||
if (!fat16_is_file_valid(file)) |
||||
fat16_next(file);*/ |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** Open previous file in the directory */ |
||||
bool fat16_prev(FAT16_FILE* file) |
||||
{ |
||||
if (file->num == 0) |
||||
return false; // first file already
|
||||
|
||||
_fat16_fopen(file->fat, file, file->clu, file->num-1); |
||||
|
||||
/* // Skip bad files
|
||||
if (!fat16_is_file_valid(file)) |
||||
fat16_prev(file);*/ |
||||
|
||||
return true; |
||||
} |
||||
|
||||
|
||||
/** Open a directory */ |
||||
bool fat16_opendir(FAT16_FILE* file) |
||||
{ |
||||
// Don't open non-dirs and "." directory.
|
||||
if (!(file->attribs & FA_DIR) || file->type == FT_SELF) |
||||
return false; |
||||
|
||||
_fat16_fopen(file->fat, file, file->clu_start, 0); |
||||
return true; |
||||
} |
||||
|
||||
|
||||
void fat16_open_root(const FAT16* fat, FAT16_FILE* file) |
||||
{ |
||||
_fat16_fopen(fat, file, 0, 0); |
||||
} |
@ -0,0 +1,186 @@ |
||||
#pragma once |
||||
|
||||
/** Abstract block device interface */ |
||||
typedef struct { |
||||
// Sequential read
|
||||
void (*read)(void* dest, const uint16_t len); |
||||
// Read at address
|
||||
void (*aread)(void* dest, const uint16_t len, const uint32_t addr); |
||||
// Sequential write
|
||||
void (*write)(const void* src, const uint16_t len); |
||||
// Write at address
|
||||
void (*awrite)(const void* src, const uint16_t len, const uint32_t addr); |
||||
// Absolute seek
|
||||
void (*seek)(const uint32_t); |
||||
// Relative seek
|
||||
void (*rseek)(const uint16_t); |
||||
} BLOCKDEV; |
||||
|
||||
|
||||
// -------------------------------
|
||||
|
||||
/** file types (values don't matter) */ |
||||
typedef enum { |
||||
FT_NONE = '-', |
||||
FT_DELETED = 'x', |
||||
FT_SUBDIR = 'D', |
||||
FT_PARENT = 'P', |
||||
FT_LABEL = 'L', |
||||
FT_LFN = '~', |
||||
FT_SELF = '.', |
||||
FT_FILE = 'F' |
||||
} FAT16_FT; |
||||
|
||||
|
||||
// File Attributes (bit flags)
|
||||
#define FA_READONLY 0x01 // read only file
|
||||
#define FA_HIDDEN 0x02 // hidden file
|
||||
#define FA_SYSTEM 0x04 // system file
|
||||
#define FA_LABEL 0x08 // volume label entry, found only in root directory.
|
||||
#define FA_DIR 0x10 // subdirectory
|
||||
#define FA_ARCHIVE 0x20 // archive flag
|
||||
|
||||
|
||||
/** Boot Sector structure - INTERNAL! */ |
||||
typedef struct __attribute__((packed)) { |
||||
|
||||
// Fields loaded directly from disk:
|
||||
|
||||
// 13 bytes skipped
|
||||
uint8_t sectors_per_cluster; |
||||
uint16_t reserved_sectors; |
||||
uint8_t num_fats; |
||||
uint16_t root_entries; |
||||
// 3 bytes skipped
|
||||
uint16_t fat_size_sectors; |
||||
// 8 bytes skipped
|
||||
uint32_t total_sectors; // if "short size sectors" is used, it's copied here too
|
||||
// 7 bytes skipped
|
||||
char volume_label[11]; // space padded, no terminator
|
||||
|
||||
// Added fields:
|
||||
|
||||
uint32_t bytes_per_cluster; |
||||
|
||||
} Fat16BootSector; |
||||
|
||||
|
||||
/** FAT filesystem handle - private fields! */ |
||||
typedef struct __attribute__((packed)) { |
||||
// Backing block device
|
||||
const BLOCKDEV* dev; |
||||
|
||||
// Root directory sector start
|
||||
uint32_t rd_addr; |
||||
|
||||
// Start of first cluster (number "2")
|
||||
uint32_t data_addr; |
||||
|
||||
// Start of fat table
|
||||
uint32_t fat_addr; |
||||
|
||||
// Boot sector data struct
|
||||
Fat16BootSector bs; |
||||
} FAT16; |
||||
|
||||
|
||||
/** File handle struct */ |
||||
typedef struct __attribute__((packed)) { |
||||
|
||||
// Fields loaded directly from disk:
|
||||
|
||||
uint8_t name[8]; // Starting 0x05 converted to 0xE5, other "magic chars" left intact
|
||||
uint8_t ext[3]; |
||||
uint8_t attribs; // composed of FA_* constants
|
||||
// 12 bytes skipped
|
||||
uint16_t clu_start; |
||||
uint32_t size; |
||||
|
||||
// Added fields:
|
||||
|
||||
FAT16_FT type; |
||||
|
||||
// --- Private fields ---
|
||||
|
||||
// Cursor
|
||||
uint32_t cur_abs; // absolute position in device
|
||||
uint32_t cur_rel; // relative position in file
|
||||
uint16_t cur_clu; // cluster where the cursor is
|
||||
uint16_t cur_ofs; // offset within the active cluster
|
||||
|
||||
// File position in the directory
|
||||
uint16_t clu; // first cluster of directory
|
||||
uint16_t num; // fiel entry number
|
||||
|
||||
// pointer to FAT
|
||||
const FAT16* fat; |
||||
} FAT16_FILE; |
||||
|
||||
|
||||
/** Initialize a filesystem */ |
||||
void fat16_init(const BLOCKDEV* dev, FAT16* fat); |
||||
|
||||
/**
|
||||
* Open the first file of the root directory. |
||||
* The file may be invalid (eg. a volume label, deleted etc), |
||||
* or blank (type FT_NONE) if the filesystem is empty. |
||||
* |
||||
* Either way, the prev and next functions will work as expected. |
||||
*/ |
||||
void fat16_open_root(const FAT16* fat, FAT16_FILE* file); |
||||
|
||||
/**
|
||||
* Resolve volume label. |
||||
*/ |
||||
char* fat16_volume_label(const FAT16* fat, char* str); |
||||
|
||||
|
||||
// ----------- FILE I/O -------------
|
||||
|
||||
|
||||
/**
|
||||
* Move file cursor to a position relative to file start |
||||
* Returns false on I/O error (bad file, out of range...) |
||||
*/ |
||||
bool fat16_fseek(FAT16_FILE* file, uint32_t addr); |
||||
|
||||
|
||||
/**
|
||||
* Read bytes from file into memory |
||||
* Returns false on I/O error (bad file, out of range...) |
||||
*/ |
||||
bool fat16_fread(FAT16_FILE* file, void* target, uint32_t len); |
||||
|
||||
|
||||
|
||||
// --------- NAVIGATION ------------
|
||||
|
||||
|
||||
/** Go to previous file in the directory (false = no prev file) */ |
||||
bool fat16_prev(FAT16_FILE* file); |
||||
|
||||
|
||||
/** Go to next file in directory (false = no next file) */ |
||||
bool fat16_next(FAT16_FILE* file); |
||||
|
||||
|
||||
/** Open a directory (file is a directory entry) */ |
||||
bool fat16_opendir(FAT16_FILE* file); |
||||
|
||||
|
||||
|
||||
// -------- FILE INSPECTION -----------
|
||||
|
||||
/** Check if file is a valid entry, or long-name/label/deleted */ |
||||
bool fat16_is_file_valid(const FAT16_FILE* file); |
||||
|
||||
|
||||
/** Get opened file's type */ |
||||
FAT16_FT fat16_get_type(const FAT16_FILE* file); |
||||
|
||||
|
||||
/**
|
||||
* Resolve a file name, trim spaces and add null terminator. |
||||
* Returns the passed char*, or NULL on error. |
||||
*/ |
||||
char* fat16_display_name(const FAT16_FILE* file, char* str); |
@ -0,0 +1,2 @@ |
||||
* |
||||
!.gitignore |
@ -0,0 +1,103 @@ |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <stdint.h> |
||||
#include <stdbool.h> |
||||
|
||||
#include "fat16.h" |
||||
|
||||
|
||||
|
||||
// ------------- test bed ----------------
|
||||
|
||||
BLOCKDEV test; |
||||
FILE* testf; |
||||
|
||||
void test_seek(const uint32_t pos) |
||||
{ |
||||
fseek(testf, pos, SEEK_SET); |
||||
} |
||||
|
||||
void test_rseek(const uint16_t pos) |
||||
{ |
||||
fseek(testf, pos, SEEK_CUR); |
||||
} |
||||
|
||||
void test_read(void* dest, const uint16_t len) |
||||
{ |
||||
for (int a = 0; a < len; a++) { |
||||
fread(dest+a, 1, 1, testf); |
||||
} |
||||
} |
||||
|
||||
void test_aread(void* dest, const uint16_t len, const uint32_t addr) |
||||
{ |
||||
test_seek(addr); |
||||
test_read(dest, len); |
||||
} |
||||
|
||||
void test_write(const void* source, const uint16_t len) |
||||
{ |
||||
for (int a = 0; a < len; a++) { |
||||
fwrite(source+a, 1, 1, testf); |
||||
} |
||||
} |
||||
|
||||
void test_awrite(const void* source, const uint16_t len, const uint32_t addr) |
||||
{ |
||||
test_seek(addr); |
||||
test_write(source, len); |
||||
} |
||||
|
||||
void test_open() |
||||
{ |
||||
test.read = &test_read; |
||||
test.aread = &test_aread; |
||||
test.write = &test_write; |
||||
test.awrite = &test_awrite; |
||||
test.seek = &test_seek; |
||||
test.rseek = &test_rseek; |
||||
|
||||
testf = fopen("imgs/dump_sd.img", "rb+"); |
||||
} |
||||
|
||||
void test_close() |
||||
{ |
||||
fflush(testf); |
||||
fclose(testf); |
||||
} |
||||
|
||||
|
||||
// --- testing ---
|
||||
|
||||
int main(int argc, char const *argv[]) |
||||
{ |
||||
uint32_t i32; |
||||
uint16_t i16; |
||||
uint8_t i8; |
||||
|
||||
test_open(); |
||||
|
||||
// Initialize the FS
|
||||
FAT16 fat; |
||||
fat16_init(&test, &fat); |
||||
|
||||
FAT16_FILE file; |
||||
fat16_open_root(&fat, &file); |
||||
|
||||
char str[12]; |
||||
|
||||
printf("Disk label: %s\n", fat16_volume_label(&fat, str)); |
||||
|
||||
do { |
||||
if (!fat16_is_file_valid(&file)) continue; |
||||
|
||||
printf("File name: %s, %c, %d B\n", |
||||
fat16_display_name(&file, str), |
||||
file.type, file.size); |
||||
|
||||
} while (fat16_next(&file)); |
||||
|
||||
test_close(); |
||||
|
||||
return 0; |
||||
} |
Loading…
Reference in new issue