HEAVY speed improvement in SD/FAT write.

pull/1/head v2.1.0
Ondřej Hruška 9 years ago
parent d8e53ac598
commit 2a92e06d08
  1. 12
      lib/blockdev.h
  2. 185
      lib/fat16.c
  3. 64
      lib/fat16.h
  4. 2
      lib/sd.h
  5. 24
      lib/sd_blockdev.c
  6. 8
      lib/sd_blockdev.h
  7. 45
      lib/sd_fat.c
  8. 23
      lib/sd_fat.h
  9. 7
      lib/stream.c
  10. 35
      lib/stream.h

@ -50,5 +50,17 @@ typedef struct
*/
void (*rseek)(const int16_t offset);
/** Flush the data buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*
* Tmplementations that do not need this should provide
* a no-op function.
*/
void (*flush)(void);
} BLOCKDEV;

@ -24,7 +24,7 @@ uint16_t next_clu(const FAT16* fat, uint16_t cluster);
uint32_t clu_offs(const FAT16* fat, uint16_t cluster, uint32_t addr);
/** Read a file entry from directory (dir starting cluster, entry number) */
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num);
void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num);
/** Allocate and chain new cluster to a chain starting at given cluster */
bool append_cluster(const FAT16* fat, const uint16_t clu);
@ -42,7 +42,7 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu);
* Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name".
*/
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname);
bool dir_find_file_raw(FFILE* dir, const char* fname);
/** Write a value into FAT */
void write_fat(const FAT16* fat, const uint16_t cluster, const uint16_t value);
@ -276,10 +276,10 @@ bool free_cluster_chain(const FAT16* fat, uint16_t clu)
* Check if there is already a file of given RAW name
* Raw name - name as found on disk, not "display name".
*/
bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
bool dir_find_file_raw(FFILE* dir, const char* fname)
{
// rewind
fat16_first(dir);
ff_first(dir);
do
{
@ -299,7 +299,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
return true; // file is already open.
}
}
while (fat16_next(dir));
while (ff_next(dir));
return false;
}
@ -311,7 +311,7 @@ bool dir_find_file_raw(FAT16_FILE* dir, const char* fname)
* dir_cluster ... directory start cluster
* num ... entry number in the directory
*/
void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, const uint16_t num)
void open_file(const FAT16* fat, FFILE* file, const uint16_t dir_cluster, const uint16_t num)
{
// Resolve starting address
uint32_t addr;
@ -397,7 +397,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
}
// Init cursors
fat16_seek(file, 0);
ff_seek(file, 0);
}
@ -406,7 +406,7 @@ void open_file(const FAT16* fat, FAT16_FILE* file, const uint16_t dir_cluster, c
* Write information into a file header.
* "file" is an open handle.
*/
void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start)
void write_file_header(FFILE* file, const char* fname_raw, const uint8_t attribs, const uint16_t clu_start)
{
const BLOCKDEV* dev = file->fat->dev;
@ -442,7 +442,7 @@ void write_file_header(FAT16_FILE* file, const char* fname_raw, const uint8_t at
// =============== PUBLIC FUNCTION IMPLEMENTATIONS =================
/** Initialize a FAT16 handle */
bool fat16_init(const BLOCKDEV* dev, FAT16* fat)
bool ff_init(const BLOCKDEV* dev, FAT16* fat)
{
const uint32_t bs_a = find_bs(dev);
@ -464,7 +464,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat)
* Move file cursor to a position relative to file start
* Allows seek past end of file, will allocate new cluster if needed.
*/
bool fat16_seek(FAT16_FILE* file, uint32_t addr)
bool ff_seek(FFILE* file, uint32_t addr)
{
const FAT16* fat = file->fat;
@ -512,7 +512,7 @@ bool fat16_seek(FAT16_FILE* file, uint32_t addr)
* Check if file is a regular file or directory entry.
* Those files can be shown to user.
*/
bool fat16_is_regular(const FAT16_FILE* file)
bool ff_is_regular(const FFILE* file)
{
switch (file->type)
{
@ -530,7 +530,7 @@ bool fat16_is_regular(const FAT16_FILE* file)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len)
uint16_t ff_read(FFILE* file, void* target, uint16_t len)
{
if (file->cur_abs == 0xFFFF)
return 0; // file at the end already
@ -580,14 +580,23 @@ uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len)
}
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
bool ff_write_str(FFILE* file, const char* source)
{
uint16_t len = 0;
for (; source[len] != 0; len++);
return ff_write(file, source, len);
}
bool ff_write(FFILE* file, const void* source, uint32_t len)
{
const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev;
if (file->cur_abs == 0xFFFF)
return false; // file at the end already
return false; // file past it's end (rare)
// Attempt to write past end of file
if (file->cur_rel + len >= file->size)
@ -596,14 +605,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
// Seek to the last position
// -> fseek will allocate clusters
if (!fat16_seek(file, pos_start + len))
if (!ff_seek(file, pos_start + len))
return false; // error in seek
// Write starts beyond EOF - creating a zero-filled "hole"
if (file->cur_rel > file->size)
if (pos_start > file->size + 1)
{
// Seek to the end of valid data
fat16_seek(file, file->size);
ff_seek(file, file->size);
// fill space between EOF and start-of-write with zeros
uint32_t fill = pos_start - file->size;
@ -631,31 +640,44 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
}
}
// Save new size
fat16_resize(file, pos_start + len);
// Store new size
file->size = pos_start + len;
// Seek back to where it was before
fat16_seek(file, pos_start);
ff_seek(file, pos_start);
} // (end zerofill)
// write the data
while (len > 0)
{
// How much can be stored in this cluster
const uint16_t chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len);
// store the chunk
dev->seek(file->cur_abs);
dev->store(source, chunk);
uint16_t chunk;
// advance cursors
file->cur_abs += chunk;
file->cur_rel += chunk;
file->cur_ofs += chunk;
if (len == 1)
{
dev->write(*((uint8_t*)source));
file->cur_abs++;
file->cur_rel++;
file->cur_ofs++;
chunk = 1;
// Pointer arith!
source += chunk; // advance the source pointer
}
else
{
// How much can be stored in this cluster
chunk = MIN(fat->bs.bytes_per_cluster - file->cur_ofs, len);
dev->store(source, chunk);
// advance cursors
file->cur_abs += chunk;
file->cur_rel += chunk;
file->cur_ofs += chunk;
// Pointer arith!
source += chunk; // advance the source pointer
}
// detect cluster overflow
if (file->cur_ofs >= fat->bs.bytes_per_cluster)
@ -676,7 +698,7 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len)
/** Open next file in the directory */
bool fat16_next(FAT16_FILE* file)
bool ff_next(FFILE* file)
{
const FAT16* fat = file->fat;
const BLOCKDEV* dev = fat->dev;
@ -700,7 +722,7 @@ bool fat16_next(FAT16_FILE* file)
/** Open previous file in the directory */
bool fat16_prev(FAT16_FILE* file)
bool ff_prev(FFILE* file)
{
if (file->num == 0)
return false; // first file already
@ -712,14 +734,14 @@ bool fat16_prev(FAT16_FILE* file)
/** Rewind to first file in directory */
void fat16_first(FAT16_FILE* file)
void ff_first(FFILE* file)
{
open_file(file->fat, file, file->clu, 0);
}
/** Open a directory denoted by the file. */
bool fat16_opendir(FAT16_FILE* dir)
bool ff_opendir(FFILE* dir)
{
// Don't open non-dirs and "." directory.
if (!(dir->attribs & FA_DIR) || dir->type == FT_SELF)
@ -730,7 +752,7 @@ bool fat16_opendir(FAT16_FILE* dir)
}
void fat16_root(const FAT16* fat, FAT16_FILE* file)
void ff_root(const FAT16* fat, FFILE* file)
{
open_file(fat, file, 0, 0);
}
@ -741,16 +763,16 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file)
* If file is found, "dir" will contain it's handle.
* Either way, "dir" gets modified and you may need to rewind it afterwards.
*/
bool fat16_find(FAT16_FILE* dir, const char* name)
bool ff_open(FFILE* dir, const char* name)
{
char fname[11];
fat16_rawname(name, fname);
ff_rawname(name, fname);
return dir_find_file_raw(dir, fname);
}
/** Go through a directory, and "open" first FT_NONE or FT_DELETED file entry. */
bool find_empty_file_slot(FAT16_FILE* file)
bool find_empty_file_slot(FFILE* file)
{
const uint16_t clu = file->clu;
const FAT16* fat = file->fat;
@ -795,15 +817,15 @@ bool find_empty_file_slot(FAT16_FILE* file)
bool fat16_mkfile(FAT16_FILE* file, const char* name)
bool ff_newfile(FFILE* file, const char* name)
{
// Convert filename to zero padded raw string
char fname[11];
fat16_rawname(name, fname);
ff_rawname(name, fname);
// Abort if file already exists
bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir
ff_first(file); // rewind dir
if (exists)
return false; // file already exists in the dir.
@ -823,15 +845,15 @@ bool fat16_mkfile(FAT16_FILE* file, const char* name)
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool fat16_mkdir(FAT16_FILE* file, const char* name)
bool ff_mkdir(FFILE* file, const char* name)
{
// Convert filename to zero padded raw string
char fname[11];
fat16_rawname(name, fname);
ff_rawname(name, fname);
// Abort if file already exists
bool exists = dir_find_file_raw(file, fname);
fat16_first(file); // rewind dir
ff_first(file); // rewind dir
if (exists)
return false; // file already exusts in the dir.
@ -854,20 +876,20 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name)
write_file_header(file, ".. ", FA_DIR, parent_clu);
// rewind.
fat16_first(file);
ff_first(file);
return true;
}
char* fat16_disk_label(const FAT16* fat, char* label_out)
char* ff_disk_label(const FAT16* fat, char* label_out)
{
FAT16_FILE first;
fat16_root(fat, &first);
FFILE first;
ff_root(fat, &first);
if (first.type == FT_LABEL)
{
return fat16_dispname(&first, label_out);
return ff_dispname(&first, label_out);
}
// find where spaces end
@ -890,7 +912,7 @@ char* fat16_disk_label(const FAT16* fat, char* label_out)
}
char* fat16_dispname(const FAT16_FILE* file, char* disp_out)
char* ff_dispname(const FFILE* file, char* disp_out)
{
// Cannot get name for special files
if (file->type == FT_NONE || // not-yet-used directory location
@ -940,7 +962,7 @@ char* fat16_dispname(const FAT16_FILE* file, char* disp_out)
}
char* fat16_rawname(const char* disp_in, char* raw_out)
char* ff_rawname(const char* disp_in, char* raw_out)
{
uint8_t name_c = 0, wr_c = 0;
bool filling = false;
@ -1014,7 +1036,7 @@ char* fat16_rawname(const char* disp_in, char* raw_out)
}
FSAVEPOS fat16_savepos(const FAT16_FILE* file)
FSAVEPOS ff_savepos(const FFILE* file)
{
FSAVEPOS fsp;
fsp.clu = file->clu;
@ -1024,28 +1046,31 @@ FSAVEPOS fat16_savepos(const FAT16_FILE* file)
}
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos)
void ff_reopen(FFILE* file, const FSAVEPOS* pos)
{
open_file(file->fat, file, pos->clu, pos->num);
fat16_seek(file, pos->cur_rel);
ff_seek(file, pos->cur_rel);
}
/** Write new file size (also to the disk). Does not allocate clusters. */
void fat16_resize(FAT16_FILE* file, uint32_t size)
void ff_flush_file(FFILE* file)
{
const FAT16* fat = file->fat;
const BLOCKDEV* dev = file->fat->dev;
// Store open page
dev->flush();
// Store file size
// Find address for storing the size
const uint32_t addr = clu_offs(fat, file->clu, file->num * 32 + 28);
file->size = size;
dev->seek(addr);
dev->store(&size, 4);
dev->store(&(file->size), 4);
// Seek to the end of the file, to make sure clusters are allocated
fat16_seek(file, size - 1);
ff_seek(file, file->size - 1);
const uint16_t next = next_clu(fat, file->cur_clu);
if (next != 0xFFFF)
@ -1057,8 +1082,10 @@ void fat16_resize(FAT16_FILE* file, uint32_t size)
}
}
/** Low level no-check file delete and free */
void delete_file_do(FAT16_FILE* file)
void delete_file_do(FFILE* file)
{
const FAT16* fat = file->fat;
@ -1080,7 +1107,7 @@ void delete_file_do(FAT16_FILE* file)
/** Delete a simple file */
bool fat16_rmfile(FAT16_FILE* file)
bool ff_rmfile(FFILE* file)
{
switch (file->type)
{
@ -1099,15 +1126,15 @@ bool fat16_rmfile(FAT16_FILE* file)
/** Delete an empty directory */
bool fat16_rmdir(FAT16_FILE* file)
bool ff_rmdir(FFILE* file)
{
if (file->type != FT_SUBDIR)
return false; // not a subdirectory entry
const FSAVEPOS orig = fat16_savepos(file);
const FSAVEPOS orig = ff_savepos(file);
// Open the subdir
if (!fat16_opendir(file))
if (!ff_opendir(file))
return false; // could not open
// Look for valid files and subdirs in the directory
@ -1124,16 +1151,16 @@ bool fat16_rmdir(FAT16_FILE* file)
{
// Valid child file was found, aborting.
// reopen original file
fat16_reopen(file, &orig);
ff_reopen(file, &orig);
return false;
}
if (cnt < 2) cnt++;
}
while (fat16_next(file));
while (ff_next(file));
// reopen original file
fat16_reopen(file, &orig);
ff_reopen(file, &orig);
// and delete as ordinary file
delete_file_do(file);
@ -1142,7 +1169,7 @@ bool fat16_rmdir(FAT16_FILE* file)
}
bool fat16_delete(FAT16_FILE* file)
bool ff_delete(FFILE* file)
{
switch (file->type)
{
@ -1153,7 +1180,7 @@ bool fat16_delete(FAT16_FILE* file)
case FT_SUBDIR:; // semicolon needed to allow declaration after "case"
// store original file location
const FSAVEPOS orig = fat16_savepos(file);
const FSAVEPOS orig = ff_savepos(file);
// open the directory (skip "." and "..")
open_file(file->fat, file, file->clu_start, 2);
@ -1161,32 +1188,32 @@ bool fat16_delete(FAT16_FILE* file)
// delete all children
do
{
if (!fat16_delete(file))
if (!ff_delete(file))
{
// failure
// reopen original file
fat16_reopen(file, &orig);
ff_reopen(file, &orig);
return false;
}
}
while (fat16_next(file));
while (ff_next(file));
// go up and delete the dir
fat16_reopen(file, &orig);
return fat16_rmdir(file);
ff_reopen(file, &orig);
return ff_rmdir(file);
default:
// try to delete as a regular file
return fat16_rmfile(file);
return ff_rmfile(file);
}
}
bool fat16_parent(FAT16_FILE* file)
bool ff_parent(FFILE* file)
{
// open second entry of the directory
open_file(file->fat, file, file->clu, 1);
const FSAVEPOS orig = fat16_savepos(file);
const FSAVEPOS orig = ff_savepos(file);
// if it's a valid PARENT link, follow it.
if (file->type == FT_PARENT)
@ -1198,7 +1225,7 @@ bool fat16_parent(FAT16_FILE* file)
{
// in root already?
// reopen original file
fat16_reopen(file, &orig);
ff_reopen(file, &orig);
return false;
}
}

@ -99,24 +99,31 @@ typedef struct __attribute__((packed))
// Pointer to the FAT16 handle. (internal)
const FAT16* fat;
}
FAT16_FILE;
FFILE;
/**
* Store modified file metadata and flush it to disk.
*/
void ff_flush_file(FFILE* file);
/**
* Save a file "position" into a struct, for later restoration.
* Cursor is also saved.
*/
FSAVEPOS fat16_savepos(const FAT16_FILE* file);
FSAVEPOS ff_savepos(const FFILE* file);
/**
* Restore a file from a saved position.
*/
void fat16_reopen(FAT16_FILE* file, const FSAVEPOS* pos);
void ff_reopen(FFILE* file, const FSAVEPOS* pos);
/**
* Initialize the file system - store into "fat"
*/
bool fat16_init(const BLOCKDEV* dev, FAT16* fat);
bool ff_init(const BLOCKDEV* dev, FAT16* fat);
/**
@ -124,7 +131,7 @@ bool fat16_init(const BLOCKDEV* dev, FAT16* fat);
* The file may be invalid (eg. a volume label, deleted etc),
* or blank (type FT_NONE) if the filesystem is empty.
*/
void fat16_root(const FAT16* fat, FAT16_FILE* file);
void ff_root(const FAT16* fat, FFILE* file);
/**
@ -134,7 +141,7 @@ void fat16_root(const FAT16* fat, FAT16_FILE* file);
* @param fat the FAT handle
* @param label_out string to store the label in. Should have at least 12 bytes.
*/
char* fat16_disk_label(const FAT16* fat, char* label_out);
char* ff_disk_label(const FAT16* fat, char* label_out);
// ----------- FILE I/O -------------
@ -144,21 +151,26 @@ char* fat16_disk_label(const FAT16* fat, char* label_out);
* Move file cursor to a position relative to file start
* Returns false on I/O error (bad file, out of range...)
*/
bool fat16_seek(FAT16_FILE* file, uint32_t addr);
bool ff_seek(FFILE* file, uint32_t addr);
/**
* Read bytes from file into memory
* Returns number of bytes read, 0 on error.
*/
uint16_t fat16_read(FAT16_FILE* file, void* target, uint16_t len);
uint16_t ff_read(FFILE* file, void* target, uint16_t len);
/**
* Write into file at a "seek" position.
* "seek" cursor must be within (0..filesize)
*/
bool fat16_write(FAT16_FILE* file, void* source, uint32_t len);
bool ff_write(FFILE* file, const void* source, uint32_t len);
/**
* Store a 0-terminated string at cursor.
*/
bool ff_write_str(FFILE* file, const char* source);
/**
@ -167,14 +179,14 @@ bool fat16_write(FAT16_FILE* file, void* source, uint32_t len);
* file ... open directory; new file is opened into this handle.
* name ... name of the new file, including extension
*/
bool fat16_mkfile(FAT16_FILE* file, const char* name);
bool ff_newfile(FFILE* file, const char* name);
/**
* Create a sub-directory of given name.
* Directory is allocated and populated with entries "." and ".."
*/
bool fat16_mkdir(FAT16_FILE* file, const char* name);
bool ff_mkdir(FFILE* file, const char* name);
/**
@ -183,26 +195,26 @@ bool fat16_mkdir(FAT16_FILE* file, const char* name);
*
* Useful mainly for shrinking.
*/
void fat16_resize(FAT16_FILE* file, uint32_t size);
void set_file_size(FFILE* file, uint32_t size);
/**
* Delete a *FILE* and free it's clusters.
*/
bool fat16_rmfile(FAT16_FILE* file);
bool ff_rmfile(FFILE* file);
/**
* Delete an empty *DIRECTORY* and free it's clusters.
*/
bool fat16_rmdir(FAT16_FILE* file);
bool ff_rmdir(FFILE* file);
/**
* Delete a file or directory, even FT_LFN and FT_INVALID.
* Directories are deleted recursively (!)
*/
bool fat16_delete(FAT16_FILE* file);
bool ff_delete(FFILE* file);
@ -210,55 +222,55 @@ bool fat16_delete(FAT16_FILE* file);
/** Go to previous file in the directory (false = no prev file) */
bool fat16_prev(FAT16_FILE* file);
bool ff_prev(FFILE* file);
/** Go to next file in directory (false = no next file) */
bool fat16_next(FAT16_FILE* file);
bool ff_next(FFILE* file);
/**
* Open a subdirectory denoted by the file.
* Provided handle changes to the first entry of the directory.
*/
bool fat16_opendir(FAT16_FILE* dir);
bool ff_opendir(FFILE* dir);
/**
* Open a parent directory. Fails in root.
* Provided handle changes to the first entry of the parent directory.
*/
bool fat16_parent(FAT16_FILE* file);
bool ff_parent(FFILE* file);
/** Jump to first file in this directory */
void fat16_first(FAT16_FILE* file);
void ff_first(FFILE* file);
/**
* Find a file with given "display name" in this directory.
* Find a file with given "display name" in this directory, and open it.
* If file is found, "dir" will contain it's handle.
* If file is NOT found, the handle points to the last entry of the directory.
*/
bool fat16_find(FAT16_FILE* dir, const char* name);
bool ff_open(FFILE* dir, const char* name);
// -------- FILE INSPECTION -----------
/** Check if file is a valid entry, or long-name/label/deleted */
bool fat16_is_regular(const FAT16_FILE* file);
bool ff_is_regular(const FFILE* file);
/**
* Resolve a file name, trim spaces and add null terminator.
* Returns the passed char*, or NULL on error.
*/
char* fat16_dispname(const FAT16_FILE* file, char* disp_out);
char* ff_dispname(const FFILE* file, char* disp_out);
/**
* Convert filename to zero-padded fixed length one
* Returns the passed char*.
*/
char* fat16_rawname(const char* disp_in, char* raw_out);
char* ff_rawname(const char* disp_in, char* raw_out);

@ -15,8 +15,6 @@
#include "iopins.h"
#include "spi.h"
#include "uart.h"
#include "stream.h"
/** Init SD card on SPI */
bool sd_init();

@ -16,6 +16,7 @@ uint8_t dev_read();
void dev_write(const uint8_t b);
void dev_seek(const uint32_t addr);
void dev_rseek(const int16_t offset);
void dev_flush();
/** Sector buffer */
@ -36,7 +37,7 @@ uint16_t cursor_offs;
/** Flush the buffer, if it's dirty */
void sdb_flush()
void dev_flush()
{
if (buff_dirty)
{
@ -49,11 +50,12 @@ void sdb_flush()
void load_sector(const uint32_t addr)
{
// do not load if already loaded
if (buff_valid && buff_addr == addr) {
if (buff_valid && buff_addr == addr)
{
return;
}
sdb_flush();
dev_flush();
// read entire sector
sd_read(addr, 0, buff, 0, 512);
@ -90,8 +92,17 @@ inline void handle_cursor_ov()
void dev_write(const uint8_t b)
{
load_sector(cursor_sec);
buff[cursor_offs++] = b;
buff_dirty = true;
// dirty only if changed
if (buff[cursor_offs] != b)
{
buff[cursor_offs++] = b;
buff_dirty = true;
}
else
{
cursor_offs++;
}
handle_cursor_ov();
}
@ -158,7 +169,7 @@ void dev_rseek(const int16_t offset)
/** Init SD card block device */
bool sdb_init(BLOCKDEV* dev)
{
if(!sd_init()) return false;
if (!sd_init()) return false;
dev->load = &dev_load;
dev->store = &dev_store;
@ -166,6 +177,7 @@ bool sdb_init(BLOCKDEV* dev)
dev->write = &dev_write;
dev->seek = &dev_seek;
dev->rseek = &dev_rseek;
dev->flush = &dev_flush;
return true;
}

@ -2,13 +2,5 @@
#include "blockdev.h"
/**
* Flush the sector buffer if it's dirty.
*
* Should be called after each sequence of writes,
* to avoid data loss.
*/
void sdb_flush();
/** Initialize the SD card block device */
bool sdb_init(BLOCKDEV* dev);

@ -8,27 +8,60 @@
FAT16 _fat;
BLOCKDEV _dev;
static STREAM _s;
STREAM* sdf_stream = &_s;
FFILE* stream_file;
bool stream_active = false;
void stream_tx(uint8_t b)
{
if (!stream_active) return;
ff_write(stream_file, &b, 1);
}
uint8_t stream_rx()
{
if (!stream_active) return 0;
uint8_t b;
ff_read(stream_file, &b, 1);
return b;
}
void sdf_open_stream(FFILE* file)
{
stream_active = true;
stream_file = file;
}
bool sdfat_inited = false;
bool sdfat_init()
bool sdf_init()
{
if (sdfat_inited) return true;
sdfat_inited = true;
if (!sdb_init(&_dev)) return false;
if (!fat16_init(&_dev, &_fat)) return false;
if (!ff_init(&_dev, &_fat)) return false;
sdf_stream->rx = &stream_rx;
sdf_stream->tx = &stream_tx;
return true;
}
void sdfat_root(FAT16_FILE* file)
void sdf_root(FFILE* file)
{
fat16_root(&_fat, file);
ff_root(&_fat, file);
}
void sdfat_disk_label(char* str)
void sdf_disk_label(char* str)
{
fat16_disk_label(&_fat, str);
ff_disk_label(&_fat, str);
}

@ -1,19 +1,30 @@
#pragma once
//
// FAT-on-SD helpers
// FAT-on-SD helpers.
//
// This can be used for convenience, as it does all the init for you
// and hides the implementation. All regular ff_* functions will work on the FFILE.
//
#include "fat16.h"
#include "stream.h"
/** Initialize FAT16 filesystem on a SPI-connected SD card */
bool sdfat_init();
bool sdf_init();
/** Get first file of the root folder. */
void sdfat_root(FAT16_FILE* file);
void sdf_root(FFILE* file);
/** Get a disk label. Str should have 12 chars. */
void sdfat_disk_label(char* str);
void sdf_disk_label(char* str);
extern STREAM* sdf_stream;
/** Flush the SD buffer (alis of sdb_flush()) */
#define sdfat_flush() sdb_flush()
/**
* Open a stream for a file. There can be only one stream at a time.
*
* The stream will operate at the current file's cursor, just like
* ff_read and ff_write.
*/
void sdf_open_stream(FFILE* file);

@ -18,7 +18,7 @@ void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len)
}
void put_str(const STREAM *p, char* str)
void put_str(const STREAM *p, const char *str)
{
char c;
while ((c = *str++))
@ -41,6 +41,11 @@ void put_str_P(const STREAM *p, const char* str)
static void _putnf(const STREAM *p, const uint8_t places);
void put_c(const STREAM *p, const uint8_t c)
{
p->tx(c);
}
/** Send signed int8 */
void put_u8(const STREAM *p, const uint8_t num)
{

@ -31,74 +31,75 @@ typedef struct
/** Send bytes to stream */
void put_bytes(const STREAM *p, const uint8_t* str, const uint16_t len);
void put_bytes(const STREAM *p, const uint8_t* str, uint16_t len);
/** Print string into a stream */
void put_str(const STREAM *p, char* str);
void put_str(const STREAM *p, const char *str);
/** Print a programspace string into a stream */
void put_str_P(const STREAM *p, const char* str);
/** Put a char/byte. Basically the same as p->tx() */
void put_c(const STREAM *p, uint8_t c);
/** Send signed int8 */
#define put_char(p, c) (p)->tx((c))
void put_u8(const STREAM *p, const uint8_t num);
void put_u8(const STREAM *p, uint8_t num);
/** Send unsigned int8 */
void put_i8(const STREAM *p, const int8_t num);
void put_i8(const STREAM *p, int8_t num);
/** Send unsigned int */
void put_u16(const STREAM *p, const uint16_t num);
void put_u16(const STREAM *p, uint16_t num);
/** Send signed int */
void put_i16(const STREAM *p, const int16_t num);
void put_i16(const STREAM *p, int16_t num);
/** Send unsigned long */
void put_u32(const STREAM *p, const uint32_t num);
void put_u32(const STREAM *p, uint32_t num);
/** Send signed long */
void put_i32(const STREAM *p, const int32_t num);
void put_i32(const STREAM *p, int32_t num);
/** Send unsigned int8 */
void put_x8(const STREAM *p, const uint8_t num);
void put_x8(const STREAM *p, uint8_t num);
/** Send int as hex */
void put_x16(const STREAM *p, const uint16_t num);
void put_x16(const STREAM *p, uint16_t num);
/** Send long as hex */
void put_x32(const STREAM *p, const uint32_t num);
void put_x32(const STREAM *p, uint32_t num);
/** Send long long as hex */
void put_x64(const STREAM *p, const uint64_t num);
void put_x64(const STREAM *p, uint64_t num);
// float variant doesn't make sense for 8-bit int
/** Send unsigned int as float */
void put_u16f(const STREAM *p, const uint16_t num, const uint8_t places);
void put_u16f(const STREAM *p, uint16_t num, uint8_t places);
/** Send signed int as float */
void put_i16f(const STREAM *p, const int16_t num, const uint8_t places);
void put_i16f(const STREAM *p, int16_t num, uint8_t places);
/** Send unsigned long as float */
void put_u32f(const STREAM *p, const uint32_t num, const uint8_t places);
void put_u32f(const STREAM *p, uint32_t num, uint8_t places);
/** Send signed long as float */
void put_i32f(const STREAM *p, const int32_t num, const uint8_t places);
void put_i32f(const STREAM *p, int32_t num, uint8_t places);
/** Print CR LF */

Loading…
Cancel
Save